import { _decorator, Node, v3, UITransform, instantiate, Vec3, tween, Prefab, Vec2, Sprite, sp, error, animation, Animation } from 'cc';
import { BaseViewCmpt } from '../../components/baseViewCmpt';
import { Bomb, Constant, LevelData, PageIndex } from '../../const/enumConst';
import { EventName } from '../../const/eventName';
import { LevelConfig } from '../../const/levelConfig';
import { ViewName } from '../../const/viewNameConst';
import { App } from '../../core/app';
import { SoundType } from '../../core/audioManager';
import { CocosHelper } from '../../utils/cocosHelper';
import { GlobalFuncHelper } from '../../utils/globalFuncHelper';
import { ResLoadHelper } from '../../utils/resLoadHelper';
import { ToolsHelper } from '../../utils/toolsHelper';
import { gridManagerCmpt } from './gridManagerCmpt';
import { gridCmpt } from './item/gridCmpt';
import { rocketCmpt } from './item/rocketCmpt';

const { ccclass, property } = _decorator;

@ccclass('gameViewCmpt')
export class GameViewCmpt extends BaseViewCmpt {
  /**  ui */
  private gridMgr: gridManagerCmpt = null;
  private gridNode: Node = null;
  private tempNode: Node = null;
  private effNode: Node = null;
  private target1: Node = null;
  private target2: Node = null;
  private targetBg: Node = null;
  private lbStep: Node = null;
  private spPro: Node = null;
  private star: Node = null;
  private setBombTipNode: Node = null;
  /**   */
  private gridPre: Prefab = null;
  private particlePre: Prefab = null;
  private bombPre: Prefab = null;
  private rocketPre: Prefab = null;
  private blockArr: Node[][] = []
  private blockPosArr: Vec3[][] = [];
  private hideList = [];
  /** 行列数 */
  private H: number = Constant.layCount;
  private V: number = Constant.layCount;
  private isStartTouch: boolean = false;
  private curTwo: gridCmpt[] = [];
  private isStartChange: boolean = false;
  /** 关卡数据 */
  private level: number = 0;
  private stepCount: number = 0;
  private data: LevelData = null;
  private coutArr: any[] = [];
  private curScore: number = 0;
  private starCount: number = 0;
  private isWin: boolean = false;

  private tipSp: Prefab = null;

  private setBomb: boolean = false;
  private setType: number = -1;

  private baseMapNode: Node = null;
  private baseMapPre: Prefab = null;

  gameEnd: boolean = false;


  private isAni: boolean = false;

  // 在类成员变量区添加：
  private isGameStart: boolean = false;




  onLoad() {
    for (let i = 1; i < 5; i++) {
      this[`onClick_addBtn${i}`] = this.onClickAddButton.bind(this);
      this[`onClick_toolBtn${i}`] = this.onClickToolButton.bind(this);
      this[`onClick_video${i}`] = this.onClickVideoButton.bind(this);
    }
    super.onLoad();
    App.audio.play('background1', SoundType.Music, true);
    this.gridMgr = this.viewList.get('center/gridManager').getComponent(gridManagerCmpt);
    this.gridNode = this.viewList.get('center/gridNode');
    this.baseMapNode = this.viewList.get('center/baseMapNode');
    this.tempNode = this.viewList.get('center/tempNode');
    this.effNode = this.viewList.get('center/effNode');
    this.targetBg = this.viewList.get('top/targetBg');
    this.target1 = this.viewList.get('top/target1');
    this.target2 = this.viewList.get('top/target2');
    this.lbStep = this.viewList.get('top/lbStep');
    this.spPro = this.viewList.get('top/probg/spPro');
    this.star = this.viewList.get('top/star');
    this.setBombTipNode = this.viewList.get('center/tip');

    const guidLayout = this.viewList.get("guidNode/guidLayout");
    if (guidLayout && guidLayout.parent) {
      guidLayout.parent.on(Node.EventType.TOUCH_END, this.playGuidAnimation, this);
    }
  }

  private async playGuidAnimation() {
    const hand = this.viewList.get("guidNode/hand");
    hand.active = false;
    const guidLayout = this.viewList.get("guidNode/guidLayout");
    for (let index = 1; index <= 46; index++) {
      const element = guidLayout.getChildByName(`block_${index}`);
      if (element) {
        const node201 = element.getChildByName("201");
        if (node201) {
          // 播放yingtao动画
          const yingtaoAni = node201.getChildByName("yingtao")?.getComponent(Animation);
          if (yingtaoAni) {
            yingtaoAni.node.active = true;
            await new Promise<void>(resolve => {
              yingtaoAni.once(Animation.EventType.FINISHED, resolve);
              yingtaoAni.play();
            });
          }
          // 播放baozha动画
          const baozhaNode = node201.getChildByName("baozha");
          if (baozhaNode) baozhaNode.active = true;
          const baozhaAni = baozhaNode?.getComponent(Animation);
          if (baozhaAni) {
            await new Promise<void>(resolve => {
              baozhaAni.once(Animation.EventType.FINISHED, resolve);
              baozhaAni.play();
            });
          }
          // 两个动画都播放完后隐藏当前block节点
          if (yingtaoAni) yingtaoAni.node.active = false;
          if (baozhaAni) baozhaAni.node.active = false;
          // 提前在第44个动画播放完时执行后续操作
          if (index === 43) {
            const guidLayouts = this.viewList.get("guidNode/guidLayout");
            if (guidLayouts && guidLayouts.parent) {
              guidLayouts.parent.active = false;
              this.isAni = true;
              this.initDDDDD();
            }
          }
        }
      }
    }
    // 46个动画全部播放完毕
    console.log('所有46个block动画已播放完毕');

    // 彻底清理演示用的block节点，防止它们参与游戏逻辑
    const guidLayoutForCleanup = this.viewList.get("guidNode/guidLayout");
    if (guidLayoutForCleanup) {
      // 销毁所有演示用的block节点
      for (let index = 1; index <= 46; index++) {
        const element = guidLayoutForCleanup.getChildByName(`block_${index}`);
        if (element) {
          element.destroy();
        }
      }
      // 或者禁用整个guidLayout
      guidLayoutForCleanup.active = false;
    }
  }

  protected async start(): Promise<void> {
    // Advertise.showVideoAds();
  }

  addEvents() {
    super.addEvents();
    App.event.on(EventName.Game.TouchStart, this.evtTouchStart, this);
    App.event.on(EventName.Game.TouchMove, this.evtTouchMove, this);
    App.event.on(EventName.Game.TouchEnd, this.evtTouchEnd, this);
    App.event.on(EventName.Game.ContinueGame, this.evtContinueGame, this);
    App.event.on(EventName.Game.Restart, this.evtRestart, this);
  }

  /** 初始化 */
  async loadExtraData(lv: number) {
    this.level = lv;
    if (this.isAni) {
      this.initDDDDD();
    }
  }

  async initDDDDD() {
    this.scheduleOnce(() => {
      this.handleTimePro();
    }, 1)

    this.data = await LevelConfig.getLevelData(this.level);
    if (this.data.mapData[0].m_id.indexOf(4) >= 0 || this.data.mapData[0].m_id.indexOf(5) >= 0) {
      if (this.data.mapData[0].m_id.length > 3) {
        this.data.mapData[0].m_id = [0, 1, 2, 3]
      } else {
        let inx = this.data.mapData[0].m_id.length;
        this.data.mapData[0].m_id = []
        for (let i = 0; i < inx; i++) {
          this.data.mapData[0].m_id.push(i);
        }

      }
    }
    App.gameLogic.blockCount = this.data.blockCount;
    this.setLevelInfo();
    this.setBomb = false;
    this.setBombTipNode.active = false;
    if (!this.gridPre) {
      this.gridPre = await ResLoadHelper.loadPieces(ViewName.Pieces.grid);
      this.particlePre = await ResLoadHelper.loadPieces(ViewName.Pieces.particle);
      this.rocketPre = await ResLoadHelper.loadPieces(ViewName.Pieces.rocket);
      this.bombPre = await ResLoadHelper.loadPieces(ViewName.Pieces.bomb);
      this.tipSp = await ResLoadHelper.loadPieces(ViewName.Pieces.tip);
      this.baseMapPre = await ResLoadHelper.loadPieces(ViewName.Pieces.basePre);
    }
    this.gameEnd = false;
    await this.initLayout();
  }


  /*********************************************  UI information *********************************************/
  /*********************************************  UI information *********************************************/
  /*********************************************  UI information *********************************************/
  private downTime: number = 1;
  private intervalTipsIndex: number = 0;

  /** 玩家5秒不操作就给提示 */
  handleTimePro() {
    this.schedule(() => {
      this.downTime -= 0.1;
      if (this.downTime > -0.01 && this.downTime < 0.01) {
        this.intervalTipsIndex = setInterval(() => {
          if (!this.isValid) return;
          this.onClick_tipsBtn();
        }, 3000);
      }
    }, 0.06);
  }

  resetTimeInterval() {
    clearInterval(this.intervalTipsIndex);
    this.downTime = 1;
  }

  getTimeInterval() {
    return this.downTime;
  }

  /** 设置关卡信息 */
  setLevelInfo() {
    let data = this.data;
    let idArr = data.mapData[0].m_id;
    let ctArr = data.mapData[0].m_ct;
    this.coutArr = [];
    for (let i = 0; i < idArr.length; i++) {
      let count = LevelConfig.getLevelTargetCount(data.mapData, i);
      let temp = [idArr[i], count];
      // if (ctArr[i] < 10) {
      //     temp = [idArr[i], count];
      // }
      this.coutArr.push(temp);
    }
    let steps = this.data.moveCount;
    this.stepCount = steps;
    this.updateTargetCount();
    this.updateStep();
    this.updateScorePercent();
  }


  /** 更新消除目标数量 */
  updateTargetCount() {
    let arr = this.coutArr;
    this.target1.active = arr.length <= 2;
    this.target2.active = arr.length > 2;
    let target = arr.length <= 2 ? this.target1 : this.target2;
    target.children.forEach((item, idx) => {
      item.active = idx < arr.length;
      if (idx < arr.length) {
        item.getComponent(gridCmpt).setType(arr[idx][0]);
        item.getComponent(gridCmpt).setCount(arr[idx][1]);
      }
    });
    this.checkResult();
  }

  /** 更新星级进度和积分 */
  updateScorePercent() {
    let arr = this.data.scores;
    let percent = this.curScore / arr[arr.length - 1] < 1 ? this.curScore / arr[arr.length - 1] : 1;
    let width = 190 * percent;
    this.spPro.getComponent(UITransform).width = width;
    this.star.children.forEach((item, idx) => {
      let per = arr[idx] / arr[arr.length - 1];
      item.setPosition(v3(per * 180, 0, 1));
      item.getChildByName('s').active = this.curScore >= arr[idx];
      if (this.curScore >= arr[idx]) {
        this.starCount = idx + 1;
      }
    });
  }

  /** 更新步数 */
  updateStep() {
    if (this.stepCount < 0) this.stepCount = 0;
    CocosHelper.updateLabelText(this.lbStep, this.stepCount);
  }

  /** 结束检测 */
  checkResult() {
    if (this.isWin) return;
    if (App.gameLogic.decModel) return;
    let count = 0;
    for (let i = 0; i < this.coutArr.length; i++) {
      if (this.coutArr[i][1] == 0) {
        count++;
      }
    }
    if (count >= this.coutArr.length) {
      // win
      this.isWin = true;
      this.gameEnd = true;
      if (this.stepCount > 0) {

        //丢炸弹
        this.handleLastSteps();
      } else {
        let view = App.view.getViewByName(ViewName.Single.eResultView);
        if (!view) {
          App.view.openView(ViewName.Single.eResultView, this.level, true, this.coutArr, this.starCount);
        }
      }
    } else if (this.stepCount <= 0 && count != this.coutArr.length) {
      //lose
      App.view.openView(ViewName.Single.eResultView, this.level, false, this.coutArr);
    }
  }

  /** 过关，处理剩余步数 */
  async handleLastSteps() {
    let step = this.stepCount;
    for (let i = 0; i < step; i++) {
      await ToolsHelper.delayTime(0.1);
      this.stepCount--;
      this.updateStep();
      this.throwTools();
    }
    await ToolsHelper.delayTime(1);
    this.checkAllBomb(true);
  }

  /** 检测网格中是否还有炸弹 */
  async checkAllBomb(result: boolean) {
    if (!this.isValid) return;
    let isHaveBomb: boolean = false;
    for (let i = 0; i < this.H; i++) {
      for (let j = 0; j < this.V; j++) {
        let item = this.blockArr[i][j];
        if (item && this.isBomb(item.getComponent(gridCmpt))) {
          isHaveBomb = true;
          this.handleBomb(item.getComponent(gridCmpt), result);
        }
      }
    }
    await ToolsHelper.delayTime(1);
    if (!isHaveBomb) {
      let view = App.view.getViewByName(ViewName.Single.eResultView);
      console.log("没有炸弹了，一切都结束了")
      if (!view) {
        App.view.openView(ViewName.Single.eResultView, this.level, true, this.coutArr, this.starCount);
      }
    }
  }

  throwTools(bombType: number = -1, worldPosition: Vec3 = null) {
    App.audio.play("prop_missle")
    let originPos = worldPosition || this.lbStep.worldPosition;
    let p1 = this.effNode.getComponent(UITransform).convertToNodeSpaceAR(originPos);
    let particle = instantiate(this.particlePre);
    this.effNode.addChild(particle);
    particle.setPosition(p1);
    particle.children.forEach(item => {
      item.active = item.name == "move";
    });
    let item: gridCmpt = this.getRandomBlock();
    if (item) {
      let p2 = this.effNode.getComponent(UITransform).convertToNodeSpaceAR(item.node.worldPosition);
      this.resetTimeInterval();
      tween(particle).to(1, { position: p2 }).call(() => {
        particle.destroy();
        let rand = bombType == -1 ? Math.floor(Math.random() * 3) + 8 : bombType;
        item && item.setType(rand);
      }).start();
    }
  }

  getRandomBlock() {
    let h = Math.floor(Math.random() * this.H);
    let v = Math.floor(Math.random() * this.V);
    if (this.blockArr[h][v] && this.blockArr[h][v].getComponent(gridCmpt).type < 7) {
      return this.blockArr[h][v].getComponent(gridCmpt);
    } else {
      return this.getRandomBlock();
    }
  }

  evtContinueGame() {
    this.stepCount += 5;
    this.isStartChange = false;
    this.isStartTouch = false;
    this.updateStep();
  }

  /*********************************************  gameLogic *********************************************/
  /*********************************************  gameLogic *********************************************/

  /*********************************************  gameLogic *********************************************/
  /** 触控事件（开始） */
  async evtTouchStart(p: Vec2) {
    console.log(this.isStartTouch, this.isStartChange)
    if (this.getTimeInterval() > 0) return;
    this.handleProtected();
    if (this.isStartChange) return;
    if (this.isStartTouch) return;
    if (this.stepCount <= 0 && !App.gameLogic.decModel) {
      App.view.showMsgTips("步数不足");
      App.view.openView(ViewName.Single.eResultView, this.level, false, this.coutArr);
      return;
    }
    let pos = this.gridNode.getComponent(UITransform).convertToNodeSpaceAR(new Vec3(p.x, p.y, 1));
    let bc = this.checkClickOnBlock(pos);
    this.curTwo = [];

    if (this.setBomb) {
      if (bc && bc.getComponent(gridCmpt).type < 7) {
        bc.getComponent(gridCmpt).setType(this.setType);
        this.setBomb = false;
        this.setBombTipNode.active = false;
      }

    } else {
      if (bc) {
        bc.setSelected(true);
        this.curTwo.push(bc);
        console.log(bc.data);
        this.isStartTouch = true;
      }
    }

    // await this.checkMoveDown();
  }

  /** 触控事件（滑动） */
  evtTouchMove(p: Vec2) {
    if (this.isStartChange) return;
    if (!this.isStartTouch) return;
    let pos = this.gridNode.getComponent(UITransform).convertToNodeSpaceAR(new Vec3(p.x, p.y, 1));
    let bc = this.checkClickOnBlock(pos);
    if (bc && App.gameLogic.isNeighbor(bc, this.curTwo[0])) {
      bc.setSelected(true);
      this.curTwo.push(bc);
      this.isStartChange = true;
      this.startChangeCurTwoPos();
    }
  }

  /** 触控事件（结束 ） */
  async evtTouchEnd(p: Vec2) {
    if (this.isStartChange) return;
    if (!this.isStartTouch) return;
    let pos = this.gridNode.getComponent(UITransform).convertToNodeSpaceAR(new Vec3(p.x, p.y, 1));
    let bc = this.checkClickOnBlock(pos);
    /** 点到炸弹 */
    if (bc && (this.isBomb(bc)) && this.curTwo.length == 1) {
      await this.handleBomb(bc);
    }
    this.isStartTouch = false;
    this.isStartChange = false;
    this.resetSelected();
    if (!this.isGameStart) {
      this.isGameStart = true;
      this.checkAgain();
    }
  }

  private isRecording: boolean = false;

  /** 这里做一层保护措施，以防玩家预料之外的骚操作引起的游戏中断 */
  handleProtected() {
    if ((this.isStartChange || this.isStartTouch) && !this.isRecording) {
      this.isRecording = true;
      this.scheduleOnce(() => {
        if (this.isValid) {
          this.isRecording = false;
          this.isStartChange = false;
          this.isStartTouch = false;
        }
      }, 5)
    }
  }

  /** 是否是炸弹 */
  isBomb(bc: gridCmpt) {
    return bc.type >= 8 && bc.type <= 12
  }

  /**
   * 是否是水果
   * @param bc
   */
  isFuirt(bc: gridCmpt) {
    return bc.type < 6

  }

  /** 是否是炸弹 */
  async handleBomb(bc: gridCmpt, isResult: boolean = false) {
    if (this.isBomb(bc)) {
      // 要销毁的格子
      let bombList = [];
      let list2 = [];
      // 第一次获取要销毁的格子数据
      let list: gridCmpt[] = await this.getBombList(bc);
      bombList.push(list);
      // 循环检测，看之前要销毁的里面有没有炸弹，有的话继续获取添加
      for (let i = 0; i < list.length; i++) {
        if (list[i].h == bc.h && list[i].v == bc.v) continue;  // 去重，去除跟自己一致的
        if (this.isBomb(list[i])) {
          bombList.push(await this.getBombList(list[i]));
        }
      }
      let func = (pc: gridCmpt) => {
        for (let i = 0; i < list2.length; i++) {
          if (list2[i].h == pc.h && list2[i].v == pc.v) {
            return true;
          }
        }
        return false;
      }
      // 循环检测，去除因上面多次查询取到的重复数据
      for (let i = 0; i < bombList.length; i++) {
        for (let j = 0; j < bombList[i].length; j++) {
          let item = bombList[i][j];
          if (!func(item)) {
            list2.push(item);
          }
        }
      }



      // 消除这些
      await this.handleSamelistBomb(list2);
      await this.checkAgain(isResult);
      return true;
    }
    return false;
  }

  /** 是否两个都是炸弹 */
  async handleBombAll(bc: gridCmpt, bc1: gridCmpt, isResult: boolean = false) {
    if (this.isBomb(bc) && this.isBomb(bc1)) {
      // 要销毁的格子
      let bombList = [];
      let list2 = [];
      // 第一次获取要销毁的格子数据
      let list: gridCmpt[] = await this.getBombListByAll(bc, bc1);
      bombList.push(list);
      // 循环检测，看之前要销毁的里面有没有炸弹，有的话继续获取添加

      let allZhu = [];

      for (let i = 0; i < list.length; i++) {
        if (list[i].h == bc.h && list[i].v == bc.v) continue;  // 去重，去除跟自己一致的
        if (list[i].h == bc1.h && list[i].v == bc1.v) continue;  // 去重，去除跟自己一致的
        if (this.isBomb(list[i])) {
          // if (list[i].type == Bomb.zhuqingting) {
          //   allZhu.push(list[i]);
          // } else {
          bombList.push(await this.getBombList(list[i]));
          // }
        }
      }
      if (allZhu.length > 0) {
        for (let i = 0; i < allZhu.length; i++) {
          // bombList.push(this.flyZhuNow(allZhu[i]));
        }
        await ToolsHelper.delayTime(1.1);

      }
      let func = (pc: gridCmpt) => {
        for (let i = 0; i < list2.length; i++) {
          if (list2[i].h == pc.h && list2[i].v == pc.v) {
            return true;
          }
        }
        return false;
      }
      // 循环检测，去除因上面多次查询取到的重复数据
      for (let i = 0; i < bombList.length; i++) {
        for (let j = 0; j < bombList[i].length; j++) {
          let item = bombList[i][j];
          if (!func(item)) {
            list2.push(item);
          }
        }
      }



      // 消除这些
      await this.handleSamelistBomb(list2);
      await this.checkAgain(isResult);
      return true;
    }
    return false;
  }


  flyZhuNow(bc: gridCmpt): gridCmpt[] {
    let list: gridCmpt[] = [];
    for (let i = bc.h - 1; i < bc.h + 2 && i < this.H; i++) {
      if (i < 0) continue;
      let item = this.blockArr[i][bc.v];
      if (item) {
        list.push(item.getComponent(gridCmpt));
      }
    }
    for (let j = bc.v - 1; j < bc.v + 2 && j < this.V; j++) {
      if (j < 0) continue;
      let item = this.blockArr[bc.h][j];
      if (item) {
        list.push(item.getComponent(gridCmpt));
      }
    }
    // let number = list.findIndex(v=>v.uuid == bc.uuid);
    // console.log(number)
    // list.splice(number,1);
    // console.error('先炸掉一部分123')
    // let aa= await this.handleSamelistBombBefore(list);
    // list = [bc];

    this.getCount = 0;

    let mathTarget = this.getMathTarget();
    console.log(mathTarget)
    let block = instantiate(this.gridPre);
    this.tempNode.addChild(block);
    block.getComponent(gridCmpt).initData(bc.h, bc.v, bc.type);
    let worldPosition = bc.node.position;
    block.setPosition(worldPosition);
    // block.getComponent(gridCmpt).setFly()

    let worldPosition1 = mathTarget.position;
    const startPos = worldPosition;
    const controlPos = worldPosition.x == worldPosition1.x ?
      v3((worldPosition.x + worldPosition1.x) / 2,
        (worldPosition.y + worldPosition1.y) / 2 + 150, 0) :
      v3((worldPosition.x + worldPosition1.x) / 2 - 100,
        (worldPosition.y + worldPosition1.y) / 2, 0);

    const endPos = worldPosition1

    const tempVec3 = v3();
    bc.node.active = false;

    // 三维空间的缓动

    const quadraticCurve = (t: number, p1: Vec3, cp: Vec3, p2: Vec3, out: Vec3) => {

      out.x = (1 - t) * (1 - t) * p1.x + 2 * t * (1 - t) * cp.x + t * t * p2.x;

      out.y = (1 - t) * (1 - t) * p1.y + 2 * t * (1 - t) * cp.y + t * t * p2.y;

      out.z = (1 - t) * (1 - t) * p1.z + 2 * t * (1 - t) * cp.z + t * t * p2.z;

    }


    tween(block)
      .to(1, { position: endPos }, {
        onUpdate: (target, ratio) => {

          quadraticCurve(ratio, startPos, controlPos, endPos, tempVec3);
          // console.log(ratio)

          block.setPosition(tempVec3);

        }
      })
      .call(() => {
        if (!bc.node || !bc.node.isValid) {

        } else {
          bc.node.active = true;
          bc.node.setPosition(worldPosition1);
          block.destroy();

        }

      })
      .start();

    if (mathTarget && mathTarget.isValid) {
      list.push(mathTarget?.getComponent(gridCmpt));

    }
    return list;

  }

  /**
   * 竹蜻蜓飞
   * @param bc
   */
  async flyZhuQingTing(bc: gridCmpt): Promise<gridCmpt> {

    return new Promise(async resolve => {
      console.log(bc.type)
      this.getCount = 0;

      let mathTarget = this.getMathTarget();
      console.log(mathTarget)
      let block = instantiate(this.gridPre);
      this.tempNode.addChild(block);
      block.getComponent(gridCmpt).initData(bc.h, bc.v, bc.type);
      let worldPosition = bc.node.position;
      block.setPosition(worldPosition);
      // block.getComponent(gridCmpt).setFly()

      let worldPosition1 = mathTarget.position;
      const startPos = worldPosition;
      const controlPos = worldPosition.x == worldPosition1.x ?
        v3((worldPosition.x + worldPosition1.x) / 2,
          (worldPosition.y + worldPosition1.y) / 2 + 150, 0) :
        v3((worldPosition.x + worldPosition1.x) / 2 - 100,
          (worldPosition.y + worldPosition1.y) / 2, 0);

      const endPos = worldPosition1

      const tempVec3 = v3();
      bc.node.active = false;

      // 三维空间的缓动

      const quadraticCurve = (t: number, p1: Vec3, cp: Vec3, p2: Vec3, out: Vec3) => {

        out.x = (1 - t) * (1 - t) * p1.x + 2 * t * (1 - t) * cp.x + t * t * p2.x;

        out.y = (1 - t) * (1 - t) * p1.y + 2 * t * (1 - t) * cp.y + t * t * p2.y;

        out.z = (1 - t) * (1 - t) * p1.z + 2 * t * (1 - t) * cp.z + t * t * p2.z;

      }


      tween(block)
        .to(1, { position: endPos }, {
          onUpdate: (target, ratio) => {

            quadraticCurve(ratio, startPos, controlPos, endPos, tempVec3);
            // console.log(ratio)

            block.setPosition(tempVec3);

          }
        })
        .call(() => {
          block.destroy();

          if (!bc.node || !bc.node.isValid) {
            resolve(null);
          } else {
            bc.node.active = true;
            bc.node.setPosition(worldPosition1);
            if (mathTarget && mathTarget.isValid) {
              resolve(mathTarget?.getComponent(gridCmpt));

            } else {
              resolve(null);
            }
          }

        })
        .start();


    });


  }

  /**
   * 竹蜻蜓飞
   * @param bc
   */
  async flyZhuQingTingAndProp(bc: gridCmpt, two: gridCmpt): Promise<gridCmpt> {

    return new Promise(async resolve => {
      this.getCount = 0;
      let t = two.type;

      let mathTarget = this.getMathTarget();
      console.log(mathTarget)
      let block = instantiate(this.gridPre);
      this.tempNode.addChild(block);
      block.getComponent(gridCmpt).initData(bc.h, bc.v, bc.type);
      let worldPosition = bc.node.position;
      block.setPosition(worldPosition);
      // block.getComponent(gridCmpt).setFly();


      let block1 = instantiate(this.gridPre);
      this.tempNode.addChild(block1);
      block1.getComponent(gridCmpt).initData(bc.h, bc.v, two.type);
      block1.setPosition(worldPosition);

      let worldPosition1 = mathTarget.position;
      const startPos = worldPosition;
      const controlPos = worldPosition.x == worldPosition1.x ?
        v3((worldPosition.x + worldPosition1.x) / 2,
          (worldPosition.y + worldPosition1.y) / 2 + 150, 0) :
        v3((worldPosition.x + worldPosition1.x) / 2 - 100,
          (worldPosition.y + worldPosition1.y) / 2, 0);

      const endPos = worldPosition1

      const tempVec3 = v3();
      bc.node.active = false;
      two.node.active = false;

      // 三维空间的缓动

      const quadraticCurve = (t: number, p1: Vec3, cp: Vec3, p2: Vec3, out: Vec3) => {

        out.x = (1 - t) * (1 - t) * p1.x + 2 * t * (1 - t) * cp.x + t * t * p2.x;

        out.y = (1 - t) * (1 - t) * p1.y + 2 * t * (1 - t) * cp.y + t * t * p2.y;

        out.z = (1 - t) * (1 - t) * p1.z + 2 * t * (1 - t) * cp.z + t * t * p2.z;

      }


      tween(block)
        .to(1, { position: endPos }, {
          onUpdate: (target, ratio) => {

            quadraticCurve(ratio, startPos, controlPos, endPos, tempVec3);
            // console.log(ratio)

            block.setPosition(tempVec3);

          }
        })
        .call(() => {
          bc.node.active = true;
          bc.node.setPosition(worldPosition1);
          let worldPosition = mathTarget.worldPosition
          this.flyItem(mathTarget.getComponent(gridCmpt).type, worldPosition);
          mathTarget.getComponent(gridCmpt).setType(t);
          console.log('变成：：' + t)
          block.destroy();

          resolve(mathTarget.getComponent(gridCmpt));
        })
        .start();
      tween(block1)
        .to(1, { position: endPos }, {
          onUpdate: (target, ratio) => {

            quadraticCurve(ratio, startPos, controlPos, endPos, tempVec3);
            // console.log(ratio)

            block1.setPosition(tempVec3);

          }
        })
        .call(() => {
          two.node.active = false;
          two.node.setPosition(worldPosition1);

          block1.destroy();
        })
        .start();


    });


  }

  getCount: number = 0;

  /**
   * 返回本关内一个随机的目标元素
   */
  getMathTarget(): Node {
    this.getCount++;
    if (this.getCount > 20) {
      return this.blockArr[0][0];
    }

    let count = 0;
    for (let i = 0; i < this.coutArr.length; i++) {
      if (this.coutArr[i][1] == 0) {
        count++;
      }
    }
    let list = []

    for (let i = 0; i < this.H; i++) {
      for (let j = 0; j < this.V; j++) {
        let item = this.blockArr[i][j];
        if (item && this.data.mapData[0].m_id.indexOf(item.getComponent(gridCmpt).type) >= 0) {
          list.push(item);
        }
      }
    }
    if (list.length == 0) {
      let numberH = Math.floor(Math.random() * this.H);
      let numberV = Math.floor(Math.random() * this.V);
      if (this.blockArr[numberH][numberV] != null && this.blockArr[numberH][numberV] != undefined) {
        let component = this.blockArr[numberH][numberV].getComponent(gridCmpt);
        if (this.data.mapData[0].m_id.indexOf(component.type) < 0) {
          if (count >= this.coutArr.length) {
            return this.blockArr[numberH][numberV];

          } else {
            return this.getMathTarget();

          }
        } else {
          return this.blockArr[numberH][numberV];
        }
      } else {
        return this.getMathTarget();
      }
    } else {
      return list[Math.floor(Math.random() * list.length)];
    }



  }

  /** 获取炸弹炸掉的糖果列表 */
  async getBombList(bc: gridCmpt): Promise<gridCmpt[]> {
    let list: gridCmpt[] = [];
    if (!bc.node?.isValid) {
      return list;
    }
    switch (bc.type) {
      case Bomb.hor:  // 横向
        for (let i = 0; i < this.H; i++) {
          let item = this.blockArr[i][bc.v];
          if (item) {
            list.push(item.getComponent(gridCmpt));
          }
        }
        App.audio.play("prop_line")
        let rocket1 = instantiate(this.rocketPre);
        this.effNode.addChild(rocket1);
        rocket1.setPosition(bc.node.position);
        rocket1.getComponent(rocketCmpt).initData(bc.type);
        break;
      case Bomb.ver:  // 竖向
        for (let i = 0; i < this.V; i++) {
          let item = this.blockArr[bc.h][i];
          if (item) {
            list.push(item.getComponent(gridCmpt));
          }
        }
        App.audio.play("prop_line")
        let rocket = instantiate(this.rocketPre);
        this.effNode.addChild(rocket);
        rocket.setPosition(bc.node.position);
        rocket.getComponent(rocketCmpt).initData(bc.type);
        break;
      case Bomb.bomb:  //炸弹
        for (let i = bc.h - 2; i < bc.h + 3 && i < this.V; i++) {
          for (let j = bc.v - 2; j < bc.v + 3 && j < this.V; j++) {
            if (i < 0 || j < 0) continue;
            let item = this.blockArr[i][j];
            if (item) {
              list.push(item.getComponent(gridCmpt));
            }
          }
        }
        App.audio.play("prop_bomb")
        break;
      // case Bomb.zhuqingting:  //竹蜻蜓
      //   for (let i = bc.h - 1; i < bc.h + 2 && i < this.H; i++) {
      //     if (i < 0) continue;
      //     let item = this.blockArr[i][bc.v];
      //     if (item) {
      //       list.push(item.getComponent(gridCmpt));
      //     }
      //   }
      //   for (let j = bc.v - 1; j < bc.v + 2 && j < this.V; j++) {
      //     if (j < 0) continue;
      //     let item = this.blockArr[bc.h][j];
      //     if (item) {
      //       list.push(item.getComponent(gridCmpt));
      //     }
      //   }
      //   // let number = list.findIndex(v=>v.uuid == bc.uuid);
      //   // console.log(number)
      //   // list.splice(number,1);
      //   // console.error('先炸掉一部分123')
      //   // let aa= await this.handleSamelistBombBefore(list);
      //   // list = [bc];

      //   let gridCmpt1 = await this.flyZhuQingTing(bc);
      //   if (gridCmpt1 != null) {
      //     list.push(gridCmpt1);

      //   }

      //   console.error('竹蜻蜓！！！')
      //   console.error(list.length)
      //   break;
      case Bomb.allSame:  // 消除同个类型
        let allType = new Map();
        for (let i = 0; i < this.H; i++) {
          for (let j = 0; j < this.V; j++) {
            let item = this.blockArr[i][j];
            if (item && !this.isBomb(item.getComponent(gridCmpt)) && this.isFuirt(item.getComponent(gridCmpt))) {
              let newVar = allType.get(item.getComponent(gridCmpt).type);
              if (newVar == undefined) {
                allType.set(item.getComponent(gridCmpt).type, 1)
              } else {
                allType.set(item.getComponent(gridCmpt).type, (newVar + 1))

              }
            }
          }
        }
        let curType = 0;
        let curNum = 0;
        allType.forEach((value, key) => {
          if (value > curNum) {
            curType = key;
            curNum = value;
          }
        })


        let node = bc.node.getChildByName('icon').getChildByName('Match11');
        node.getComponent(Sprite).enabled = false;
        node.getChildByName('a').active = true;
        if (curType < 0) curType = Math.floor(Math.random() * App.gameLogic.blockCount);
        App.audio.play("prop_missle")
        for (let i = 0; i < this.H; i++) {
          for (let j = 0; j < this.V; j++) {
            let item = this.blockArr[i][j];
            if (item && item.getComponent(gridCmpt).type == curType) {
              list.push(item.getComponent(gridCmpt));
              let particle = instantiate(this.particlePre);
              this.effNode.addChild(particle);
              particle.setPosition(bc.node.position);
              particle.children.forEach(item => {
                item.active = item.name == "move";
              });
              this.resetTimeInterval();
              tween(particle).to(0.5, { position: item.position }).call(async (particle) => {
                await ToolsHelper.delayTime(0.2);
                particle.destroy();
              }).start();
            }
          }
        }
        list.push(bc);
        await ToolsHelper.delayTime(0.7);
        break;
    }
    return list;
  }

  /** 获取炸弹炸掉的糖果列表 */
  async getBombListByAll(bc: gridCmpt, two: gridCmpt): Promise<gridCmpt[]> {
    let list: gridCmpt[] = [];
    switch (bc.type) {
      case Bomb.hor:  // 横向
        switch (two.type) {
          case Bomb.hor:
            for (let i = 0; i < this.H; i++) {
              let item = this.blockArr[i][bc.v];
              if (item) {
                list.push(item.getComponent(gridCmpt));
              }
              let item1 = this.blockArr[i][two.v];
              if (item1) {
                list.push(item1.getComponent(gridCmpt));
              }
            }
            App.audio.play("prop_line")
            let rocket1 = instantiate(this.rocketPre);
            this.effNode.addChild(rocket1);
            rocket1.setPosition(bc.node.position);
            rocket1.getComponent(rocketCmpt).initData(Bomb.hor);

            // for (let i = 0; i < this.V; i++) {
            //     let item = this.blockArr[bc.h][i];
            //     if (item) {
            //         list.push(item.getComponent(gridCmpt));
            //     }
            // }

            let rocket = instantiate(this.rocketPre);
            this.effNode.addChild(rocket);
            rocket.setPosition(two.node.position);
            rocket.getComponent(rocketCmpt).initData(Bomb.hor);
            break;
          case Bomb.ver:
            for (let i = 0; i < this.H; i++) {
              let item = this.blockArr[i][bc.v];
              if (item) {
                list.push(item.getComponent(gridCmpt));
              }
            }
            App.audio.play("prop_line")
            let rocket2 = instantiate(this.rocketPre);
            this.effNode.addChild(rocket2);
            rocket2.setPosition(bc.node.position);
            rocket2.getComponent(rocketCmpt).initData(Bomb.hor);

            for (let i = 0; i < this.V; i++) {
              let item = this.blockArr[bc.h][i];
              if (item) {
                list.push(item.getComponent(gridCmpt));
              }
            }

            let rocket3 = instantiate(this.rocketPre);
            this.effNode.addChild(rocket3);
            rocket3.setPosition(two.node.position);
            rocket3.getComponent(rocketCmpt).initData(Bomb.ver);
            break;
          case Bomb.bomb:
            console.error('baobbb')



            for (let i = 0; i < this.H; i++) {
              for (let j = two.v - 1; j < two.v + 2 && j < this.V; j++) {
                if (j < 0) {
                  continue;
                }
                let item = this.blockArr[i][j];
                if (item) {
                  list.push(item.getComponent(gridCmpt));
                }
              }

            }
            for (let i = 0; i < this.V; i++) {
              for (let j = two.h - 1; j < two.h + 2 && j < this.V; j++) {
                if (j < 0) {
                  continue;
                }
                let item = this.blockArr[j][i];
                if (item) {
                  list.push(item.getComponent(gridCmpt));
                }
              }

            }
            console.log(list.length)
            console.error('bao')

            App.audio.play("prop_bomb")

            break;
          case Bomb.allSame:
            console.log('要变得元素11')

            let allType = new Map();
            for (let i = 0; i < this.H; i++) {
              for (let j = 0; j < this.V; j++) {
                let item = this.blockArr[i][j];
                if (item && !this.isBomb(item.getComponent(gridCmpt)) && this.isFuirt(item.getComponent(gridCmpt))) {
                  let newVar = allType.get(item.getComponent(gridCmpt).type);
                  if (newVar == undefined) {
                    allType.set(item.getComponent(gridCmpt).type, 1)
                  } else {
                    allType.set(item.getComponent(gridCmpt).type, (newVar + 1))

                  }
                }
              }
            }
            let curType = 0;
            let curNum = 0;
            allType.forEach((value, key) => {
              if (value > curNum) {
                curType = key;
                curNum = value;
              }
            })

            console.log('要变得元素')

            let node = two.node.getChildByName('icon').getChildByName('Match11');
            node.getComponent(Sprite).enabled = false;
            node.getChildByName('a').active = true;
            if (curType < 0) curType = Math.floor(Math.random() * App.gameLogic.blockCount);
            App.audio.play("prop_missle")
            for (let i = 0; i < this.H; i++) {
              for (let j = 0; j < this.V; j++) {
                let item = this.blockArr[i][j];
                if (item && item.getComponent(gridCmpt).type == curType) {
                  console.log('更改元素')
                  let worldPosition = item.worldPosition
                  this.flyItem(curType, worldPosition);

                  item.getComponent(gridCmpt).setType(Math.random() > 0.5 ? Bomb.ver : Bomb.hor);
                  list.push(item.getComponent(gridCmpt));
                  let particle = instantiate(this.particlePre);
                  this.effNode.addChild(particle);
                  particle.setPosition(two.node.position);
                  particle.children.forEach(item => {
                    item.active = item.name == "move";
                  });
                  this.resetTimeInterval();
                  tween(particle).to(0.5, { position: item.position }).call(async (particle) => {
                    await ToolsHelper.delayTime(0.2);
                    particle.destroy();
                  }).start();
                }
              }
            }
            list.push(bc);
            await ToolsHelper.delayTime(0.7);

            break;
          // case Bomb.zhuqingting:
          //   for (let i = bc.h - 1; i < bc.h + 2 && i < this.H; i++) {
          //     if (i < 0) continue;
          //     let item = this.blockArr[i][bc.v];
          //     if (item) {
          //       list.push(item.getComponent(gridCmpt));
          //     }
          //   }
          //   for (let j = bc.v - 1; j < bc.v + 2 && j < this.V; j++) {
          //     if (j < 0) continue;
          //     let item = this.blockArr[bc.h][j];
          //     if (item) {
          //       list.push(item.getComponent(gridCmpt));
          //     }
          //   }
          //   let gridCmpt1 = await this.flyZhuQingTingAndProp(two, bc);
          //   list.push(gridCmpt1);
          //   break;
        }
        break;
      case Bomb.ver:  // 竖向
        switch (two.type) {
          case Bomb.hor:
            for (let i = 0; i < this.H; i++) {
              let item = this.blockArr[i][bc.v];
              if (item) {
                list.push(item.getComponent(gridCmpt));
              }
            }
            App.audio.play("prop_line")
            let rocket1 = instantiate(this.rocketPre);
            this.effNode.addChild(rocket1);
            rocket1.setPosition(two.node.position);
            rocket1.getComponent(rocketCmpt).initData(Bomb.hor);

            for (let i = 0; i < this.V; i++) {
              let item = this.blockArr[bc.h][i];
              if (item) {
                list.push(item.getComponent(gridCmpt));
              }
            }

            let rocket = instantiate(this.rocketPre);
            this.effNode.addChild(rocket);
            rocket.setPosition(bc.node.position);
            rocket.getComponent(rocketCmpt).initData(Bomb.ver);
            break;
          case Bomb.ver:


            for (let i = 0; i < this.V; i++) {
              let item = this.blockArr[bc.h][i];
              if (item) {
                list.push(item.getComponent(gridCmpt));
              }
              let item1 = this.blockArr[two.h][i];
              if (item1) {
                list.push(item1.getComponent(gridCmpt));
              }
            }
            App.audio.play("prop_line")
            let rocket2 = instantiate(this.rocketPre);
            this.effNode.addChild(rocket2);
            rocket2.setPosition(two.node.position);
            rocket2.getComponent(rocketCmpt).initData(Bomb.ver);



            let rocket3 = instantiate(this.rocketPre);
            this.effNode.addChild(rocket3);
            rocket3.setPosition(bc.node.position);
            rocket3.getComponent(rocketCmpt).initData(Bomb.ver);
            break;
          case Bomb.bomb:
            for (let i = 0; i < this.H; i++) {
              for (let j = bc.v - 1; j < bc.v + 2 && j < this.V; j++) {
                if (j < 0) {
                  continue;
                }
                let item = this.blockArr[i][j];
                if (item) {
                  list.push(item.getComponent(gridCmpt));
                }
              }

            }
            for (let i = 0; i < this.V; i++) {
              for (let j = bc.h - 1; j < bc.h + 2 && j < this.V; j++) {
                if (j < 0) {
                  continue;
                }
                let item = this.blockArr[j][i];
                if (item) {
                  list.push(item.getComponent(gridCmpt));
                }
              }

            }

            App.audio.play("prop_bomb")

            break;
          case Bomb.allSame:
            console.log('要变得元素')

            let allType = new Map();
            for (let i = 0; i < this.H; i++) {
              for (let j = 0; j < this.V; j++) {
                let item = this.blockArr[i][j];
                if (item && !this.isBomb(item.getComponent(gridCmpt)) && this.isFuirt(item.getComponent(gridCmpt))) {
                  let newVar = allType.get(item.getComponent(gridCmpt).type);
                  if (newVar == undefined) {
                    allType.set(item.getComponent(gridCmpt).type, 1)
                  } else {
                    allType.set(item.getComponent(gridCmpt).type, (newVar + 1))

                  }
                }
              }
            }
            let curType = 0;
            let curNum = 0;
            allType.forEach((value, key) => {
              if (value > curNum) {
                curType = key;
                curNum = value;
              }
            })

            console.log('要变得元素')
            console.log(curType)

            let node = two.node.getChildByName('icon').getChildByName('Match11');
            node.getComponent(Sprite).enabled = false;
            node.getChildByName('a').active = true;
            if (curType < 0) curType = Math.floor(Math.random() * App.gameLogic.blockCount);
            App.audio.play("prop_missle")
            for (let i = 0; i < this.H; i++) {
              for (let j = 0; j < this.V; j++) {
                let item = this.blockArr[i][j];
                if (item && item.getComponent(gridCmpt).type == curType) {
                  console.log('要变得元素111111')
                  let worldPosition = item.worldPosition
                  this.flyItem(curType, worldPosition);

                  item.getComponent(gridCmpt).setType(Math.random() > 0.5 ? Bomb.ver : Bomb.hor);
                  list.push(item.getComponent(gridCmpt));
                  let particle = instantiate(this.particlePre);
                  this.effNode.addChild(particle);
                  particle.setPosition(two.node.position);
                  particle.children.forEach(item => {
                    item.active = item.name == "move";
                  });
                  this.resetTimeInterval();
                  tween(particle).to(0.5, { position: item.position }).call(async (particle) => {
                    await ToolsHelper.delayTime(0.2);
                    particle.destroy();
                  }).start();
                }
              }
            }
            list.push(bc);
            await ToolsHelper.delayTime(0.7);

            break;
          // case Bomb.zhuqingting:
          //   for (let i = bc.h - 1; i < bc.h + 2 && i < this.H; i++) {
          //     if (i < 0) continue;
          //     let item = this.blockArr[i][bc.v];
          //     if (item) {
          //       list.push(item.getComponent(gridCmpt));
          //     }
          //   }
          //   for (let j = bc.v - 1; j < bc.v + 2 && j < this.V; j++) {
          //     if (j < 0) continue;
          //     let item = this.blockArr[bc.h][j];
          //     if (item) {
          //       list.push(item.getComponent(gridCmpt));
          //     }
          //   }
          //   let gridCmpt1 = await this.flyZhuQingTingAndProp(two, bc);
          //   list.push(gridCmpt1);
          //   break;
        }
        break;
      case Bomb.bomb:  //炸弹
        switch (two.type) {
          case Bomb.hor:
            console.error('baohhh')

            for (let i = 0; i < this.H; i++) {
              for (let j = bc.v - 1; j < bc.v + 2 && j < this.V; j++) {
                if (j < 0) {
                  continue;
                }
                let item = this.blockArr[i][j];
                if (item) {
                  list.push(item.getComponent(gridCmpt));
                }
              }

            }
            for (let i = 0; i < this.V; i++) {
              for (let j = bc.h - 1; j < bc.h + 2 && j < this.V; j++) {
                if (j < 0) {
                  continue;
                }
                let item = this.blockArr[j][i];
                if (item) {
                  list.push(item.getComponent(gridCmpt));
                }
              }

            }
            console.log(list.length)

            App.audio.play("prop_bomb")
            break;
          case Bomb.ver:
            for (let i = 0; i < this.H; i++) {
              for (let j = bc.v - 1; j < bc.v + 2 && j < this.V; j++) {
                if (j < 0) {
                  continue;
                }
                let item = this.blockArr[i][j];
                if (item) {
                  list.push(item.getComponent(gridCmpt));
                }
              }

            }
            for (let i = 0; i < this.V; i++) {
              for (let j = bc.h - 1; j < bc.h + 2 && j < this.V; j++) {
                if (j < 0) {
                  continue;
                }
                let item = this.blockArr[j][i];
                if (item) {
                  list.push(item.getComponent(gridCmpt));
                }
              }

            }

            App.audio.play("prop_bomb")
            break;
          case Bomb.bomb:
            console.error('bao')
            console.log(bc.v, bc.h)

            for (let i = bc.h - 4; i < bc.h + 5 && i < this.V; i++) {
              for (let j = bc.v - 4; j < bc.v + 5 && j < this.V; j++) {
                if (i < 0 || j < 0) continue;
                let item = this.blockArr[i][j];
                if (item) {
                  list.push(item.getComponent(gridCmpt));
                }
              }
            }
            console.log(list.length)

            console.error('bao')

            App.audio.play("prop_bomb")

            break;
          case Bomb.allSame:
            let allType = new Map();
            for (let i = 0; i < this.H; i++) {
              for (let j = 0; j < this.V; j++) {
                let item = this.blockArr[i][j];
                if (item && !this.isBomb(item.getComponent(gridCmpt)) && this.isFuirt(item.getComponent(gridCmpt))) {
                  let newVar = allType.get(item.getComponent(gridCmpt).type);
                  if (newVar == undefined) {
                    allType.set(item.getComponent(gridCmpt).type, 1)
                  } else {
                    allType.set(item.getComponent(gridCmpt).type, (newVar + 1))

                  }
                }
              }
            }
            let curType = 0;
            let curNum = 0;
            allType.forEach((value, key) => {
              if (value > curNum) {
                curType = key;
                curNum = value;
              }
            })


            let node = bc.node.getChildByName('icon').getChildByName('Match11');
            node.getComponent(Sprite).enabled = false;
            node.getChildByName('a').active = true;
            if (curType < 0) curType = Math.floor(Math.random() * App.gameLogic.blockCount);
            App.audio.play("prop_missle")
            for (let i = 0; i < this.H; i++) {
              for (let j = 0; j < this.V; j++) {
                let item = this.blockArr[i][j];
                if (item && item.getComponent(gridCmpt).type == curType) {
                  let worldPosition = item.worldPosition
                  this.flyItem(curType, worldPosition);
                  item.getComponent(gridCmpt).setType(Bomb.bomb);
                  list.push(item.getComponent(gridCmpt));
                  let particle = instantiate(this.particlePre);
                  this.effNode.addChild(particle);
                  particle.setPosition(bc.node.position);
                  particle.children.forEach(item => {
                    item.active = item.name == "move";
                  });
                  this.resetTimeInterval();
                  tween(particle).to(0.5, { position: item.position }).call(async (particle) => {
                    await ToolsHelper.delayTime(0.2);
                    particle.destroy();
                  }).start();
                }
              }
            }
            list.push(bc);
            await ToolsHelper.delayTime(0.7);

            break;
          // case Bomb.zhuqingting:
          //   for (let i = bc.h - 1; i < bc.h + 2 && i < this.H; i++) {
          //     if (i < 0) continue;
          //     let item = this.blockArr[i][bc.v];
          //     if (item) {
          //       list.push(item.getComponent(gridCmpt));
          //     }
          //   }
          //   for (let j = bc.v - 1; j < bc.v + 2 && j < this.V; j++) {
          //     if (j < 0) continue;
          //     let item = this.blockArr[bc.h][j];
          //     if (item) {
          //       list.push(item.getComponent(gridCmpt));
          //     }
          //   }
          //   let gridCmpt1 = await this.flyZhuQingTingAndProp(two, bc);
          //   list.push(gridCmpt1);
          //   break;
        }
        break;
      // case Bomb.zhuqingting:  //竹蜻蜓
      //   switch (two.type) {
      //     case Bomb.hor:
      //       for (let i = bc.h - 1; i < bc.h + 2 && i < this.H; i++) {
      //         if (i < 0) continue;
      //         let item = this.blockArr[i][bc.v];
      //         if (item) {
      //           list.push(item.getComponent(gridCmpt));
      //         }
      //       }
      //       for (let j = bc.v - 1; j < bc.v + 2 && j < this.V; j++) {
      //         if (j < 0) continue;
      //         let item = this.blockArr[bc.h][j];
      //         if (item) {
      //           list.push(item.getComponent(gridCmpt));
      //         }
      //       }
      //       let gridCmpt2 = await this.flyZhuQingTingAndProp(bc, two);
      //       list.push(gridCmpt2);
      //       break;
      //     case Bomb.ver:
      //       for (let i = bc.h - 1; i < bc.h + 2 && i < this.H; i++) {
      //         if (i < 0) continue;
      //         let item = this.blockArr[i][bc.v];
      //         if (item) {
      //           list.push(item.getComponent(gridCmpt));
      //         }
      //       }
      //       for (let j = bc.v - 1; j < bc.v + 2 && j < this.V; j++) {
      //         if (j < 0) continue;
      //         let item = this.blockArr[bc.h][j];
      //         if (item) {
      //           list.push(item.getComponent(gridCmpt));
      //         }
      //       }
      //       let gridCmpt3 = await this.flyZhuQingTingAndProp(bc, two);
      //       list.push(gridCmpt3);
      //       break;
      //     case Bomb.bomb:
      //       for (let i = bc.h - 1; i < bc.h + 2 && i < this.H; i++) {
      //         if (i < 0) continue;
      //         let item = this.blockArr[i][bc.v];
      //         if (item) {
      //           list.push(item.getComponent(gridCmpt));
      //         }
      //       }
      //       for (let j = bc.v - 1; j < bc.v + 2 && j < this.V; j++) {
      //         if (j < 0) continue;
      //         let item = this.blockArr[bc.h][j];
      //         if (item) {
      //           list.push(item.getComponent(gridCmpt));
      //         }
      //       }
      //       let gridCmpt4 = await this.flyZhuQingTingAndProp(bc, two);
      //       list.push(gridCmpt4);

      //       break;
      //     case Bomb.allSame:
      //       let allType = new Map();
      //       for (let i = 0; i < this.H; i++) {
      //         for (let j = 0; j < this.V; j++) {
      //           let item = this.blockArr[i][j];
      //           if (item && !this.isBomb(item.getComponent(gridCmpt))) {
      //             let newVar = allType.get(item.getComponent(gridCmpt).type);
      //             if (newVar == undefined) {
      //               allType.set(item.getComponent(gridCmpt).type, 1)
      //             } else {
      //               allType.set(item.getComponent(gridCmpt).type, (newVar + 1))

      //             }
      //           }
      //         }
      //       }
      //       let curType = 0;
      //       let curNum = 0;
      //       allType.forEach((value, key) => {
      //         if (value > curNum) {
      //           curType = key;
      //           curNum = value;
      //         }
      //       })


      //       let node = bc.node.getChildByName('icon').getChildByName('Match11');
      //       node.getComponent(Sprite).enabled = false;
      //       node.getChildByName('a').active = true;
      //       if (curType < 0) curType = Math.floor(Math.random() * App.gameLogic.blockCount);
      //       App.audio.play("prop_missle")
      //       for (let i = 0; i < this.H; i++) {
      //         for (let j = 0; j < this.V; j++) {
      //           let item = this.blockArr[i][j];
      //           if (item && item.getComponent(gridCmpt).type == curType) {
      //             let worldPosition = item.worldPosition
      //             this.flyItem(curType, worldPosition);
      //             item.getComponent(gridCmpt).setType(Bomb.zhuqingting);
      //             list.push(item.getComponent(gridCmpt));
      //             let particle = instantiate(this.particlePre);
      //             this.effNode.addChild(particle);
      //             particle.setPosition(bc.node.position);
      //             particle.children.forEach(item => {
      //               item.active = item.name == "move";
      //             });
      //             this.resetTimeInterval();
      //             tween(particle).to(0.5, { position: item.position }).call(async (particle) => {
      //               await ToolsHelper.delayTime(0.2);
      //               particle.destroy();
      //             }).start();
      //           }
      //         }
      //       }
      //       list.push(bc);
      //       await ToolsHelper.delayTime(0.7);

      //       break;
      //     case Bomb.zhuqingting:
      //       for (let i = bc.h - 1; i < bc.h + 2 && i < this.V; i++) {
      //         for (let j = bc.v - 1; j < bc.v + 2 && j < this.V; j++) {
      //           if (i < 0 || j < 0) continue;
      //           let item = this.blockArr[i][j];
      //           if (item) {
      //             list.push(item.getComponent(gridCmpt));
      //           }
      //         }
      //       }
      //       for (let i = two.h - 1; i < two.h + 2 && i < this.V; i++) {
      //         for (let j = two.v - 1; j < two.v + 2 && j < this.V; j++) {
      //           if (i < 0 || j < 0) continue;
      //           let item = this.blockArr[i][j];
      //           if (item) {
      //             list.push(item.getComponent(gridCmpt));
      //           }
      //         }
      //       }
      //       let gridCmpt5 = await this.flyZhuQingTing(bc);
      //       let gridCmpt6 = await this.flyZhuQingTing(two);
      //       list.push(gridCmpt5);
      //       list.push(gridCmpt6);
      //       if (gridCmpt5 != null) {
      //         list.push(gridCmpt5);

      //       }
      //       if (gridCmpt6 != null) {
      //         list.push(gridCmpt6);

      //       }
      //       break;
      //   }
      //   break;
      case Bomb.allSame:  // 消除同个类型
        switch (two.type) {
          case Bomb.hor:
          case Bomb.ver:
            let allType2 = new Map();
            for (let i = 0; i < this.H; i++) {
              for (let j = 0; j < this.V; j++) {
                let item = this.blockArr[i][j];
                if (item && !this.isBomb(item.getComponent(gridCmpt)) && this.isFuirt(item.getComponent(gridCmpt))) {
                  let newVar = allType2.get(item.getComponent(gridCmpt).type);
                  if (newVar == undefined) {
                    allType2.set(item.getComponent(gridCmpt).type, 1)
                  } else {
                    allType2.set(item.getComponent(gridCmpt).type, (newVar + 1))

                  }
                }
              }
            }
            let curType2 = 0;
            let curNum2 = 0;
            allType2.forEach((value, key) => {
              if (value > curNum2) {
                curType2 = key;
                curNum2 = value;
              }
            })


            let node2 = bc.node.getChildByName('icon').getChildByName('Match11');
            node2.getComponent(Sprite).enabled = false;
            node2.getChildByName('a').active = true;
            if (curType2 < 0) curType2 = Math.floor(Math.random() * App.gameLogic.blockCount);
            App.audio.play("prop_missle")
            for (let i = 0; i < this.H; i++) {
              for (let j = 0; j < this.V; j++) {
                let item = this.blockArr[i][j];
                if (item && item.getComponent(gridCmpt).type == curType2) {
                  let worldPosition = item.worldPosition
                  this.flyItem(curType2, worldPosition);
                  item.getComponent(gridCmpt).setType(Math.random() > 0.5 ? Bomb.ver : Bomb.hor);
                  list.push(item.getComponent(gridCmpt));
                  let particle = instantiate(this.particlePre);
                  this.effNode.addChild(particle);
                  particle.setPosition(bc.node.position);
                  particle.children.forEach(item => {
                    item.active = item.name == "move";
                  });
                  this.resetTimeInterval();
                  tween(particle).to(0.5, { position: item.position }).call(async (particle) => {
                    await ToolsHelper.delayTime(0.2);
                    particle.destroy();
                  }).start();
                }
              }
            }
            list.push(bc);
            await ToolsHelper.delayTime(0.7);
            break;
          case Bomb.bomb:
            // case Bomb.zhuqingting:


            let allType1 = new Map();
            for (let i = 0; i < this.H; i++) {
              for (let j = 0; j < this.V; j++) {
                let item = this.blockArr[i][j];
                if (item && !this.isBomb(item.getComponent(gridCmpt)) && this.isFuirt(item.getComponent(gridCmpt))) {
                  let newVar = allType1.get(item.getComponent(gridCmpt).type);
                  if (newVar == undefined) {
                    allType1.set(item.getComponent(gridCmpt).type, 1)
                  } else {
                    allType1.set(item.getComponent(gridCmpt).type, (newVar + 1))

                  }
                }
              }
            }
            let curType1 = 0;
            let curNum1 = 0;

            allType1.forEach((value, key) => {
              if (value > curNum1) {
                curType1 = key;
                curNum1 = value;
              }
            })


            let node1 = bc.node.getChildByName('icon').getChildByName('Match11');
            node1.getComponent(Sprite).enabled = false;
            node1.getChildByName('a').active = true;
            if (curType1 < 0) curType1 = Math.floor(Math.random() * App.gameLogic.blockCount);
            App.audio.play("prop_missle")
            for (let i = 0; i < this.H; i++) {
              for (let j = 0; j < this.V; j++) {
                let item = this.blockArr[i][j];
                if (item && item.getComponent(gridCmpt).type == curType1) {
                  let worldPosition = item.worldPosition
                  this.flyItem(curType1, worldPosition);
                  item.getComponent(gridCmpt).setType(two.type);
                  list.push(item.getComponent(gridCmpt));
                  let particle = instantiate(this.particlePre);
                  this.effNode.addChild(particle);
                  particle.setPosition(bc.node.position);
                  particle.children.forEach(item => {
                    item.active = item.name == "move";
                  });
                  this.resetTimeInterval();
                  tween(particle).to(0.5, { position: item.position }).call(async (particle) => {
                    await ToolsHelper.delayTime(0.2);
                    particle.destroy();
                  }).start();
                }
              }
            }
            list.push(bc);
            await ToolsHelper.delayTime(0.7);


            break;



          case Bomb.allSame:



            let node = bc.node.getChildByName('icon').getChildByName('Match11');
            node.getComponent(Sprite).enabled = false;
            node.getChildByName('a').active = true;

            App.audio.play("prop_missle")
            for (let i = 0; i < this.H; i++) {
              for (let j = 0; j < this.V; j++) {
                let item = this.blockArr[i][j];
                if (item) {
                  list.push(item.getComponent(gridCmpt));
                  let particle = instantiate(this.particlePre);
                  this.effNode.addChild(particle);
                  particle.setPosition(bc.node.position);
                  particle.children.forEach(item => {
                    item.active = item.name == "move";
                  });
                  this.resetTimeInterval();
                  tween(particle).to(0.5, { position: item.position }).call(async (particle) => {
                    await ToolsHelper.delayTime(0.2);
                    particle.destroy();
                  }).start();
                }
              }
            }
            list.push(bc);
            await ToolsHelper.delayTime(0.7);

            break;

        }
        break;
    }
    return list;
  }

  /** 选中状态还原 */
  resetSelected() {
    if (!this.isValid) {
      return;
    }
    this.curTwo.forEach(item => {
      if (item) {
        item.setSelected(false);
      }
    })
  }

  /** 开始交换连个选中的方块 */
  async startChangeCurTwoPos(isBack: boolean = false) {
    let time = Constant.changeTime;
    let one = this.curTwo[0], two = this.curTwo[1];
    if (!isBack) {
      App.audio.play("ui_banner_down_show")
    } else {
      App.audio.play("ui_banner_up_hide")
    }
    if (!one || !two) return;
    tween(one.node).to(time, { position: this.blockPosArr[two.h][two.v] }).start();
    tween(two.node).to(time, { position: this.blockPosArr[one.h][one.v] }).call(async () => {
      if (!isBack) {
        this.changeData(one, two);
        let isbomb3 = await this.handleBombAll(one, two);
        let isbomb1 = false;
        let isbomb2 = false;
        if (!isbomb3) {
          isbomb1 = await this.handleBomb(one);
          isbomb2 = await this.handleBomb(two);
        }

        let bool = await this.startCheckThree((bl) => {
          // 0 || other
          if (bl) {
            this.stepCount--;
            this.updateStep();
          }
        }, false, true);
        // 假如 交换的两个元素有一个是炸弹 或是 允许被消除或合成
        if (bool || (isbomb1 || isbomb2)) {
          this.checkAgain()
        } else {
          // 没满足条件各自回归原位
          console.log(this.curTwo);
          this.startChangeCurTwoPos(true);
        }
      } else {
        this.changeData(one, two);
        this.isStartChange = false;
        this.isStartTouch = false;
        this.resetSelected();
      }
    }).start();
  }

  /**
   * 是否已经加入到列表中了
   */
  private checkExist(item: gridCmpt, samelist: any[]) {
    for (let i = 0; i < samelist.length; i++) {
      for (let j = 0; j < samelist[i].length; j++) {
        let ele: gridCmpt = samelist[i][j];
        if (ele.data.h == item.data.h && ele.data.v == item.data.v) {
          return true;
        }
      }
    }
    return false;
  }

  /** 反复检查 */
  async checkAgain(isResult: boolean = false) {
    let bool = await this.startCheckThree(() => { }, isResult);
    if (bool) {
      this.checkAgain(isResult);
    } else {
      this.resetSelected();
      this.isStartChange = false;
      this.isStartTouch = false;
      if (isResult) {
        console.log(isResult);
        this.checkAllBomb(isResult);
      }
    }
  }

  /**
   * 开始检测是否有满足消除条件的存在
   * @returns bool
   */
  async startCheckThree(cb: Function = null, result: boolean = false, control: boolean = false): Promise<boolean> {
    return new Promise(async resolve => {
      let samelist = [];
      // 整个棋盘循环检测
      for (let i = 0; i < this.H; i++) {
        for (let j = 0; j < this.V; j++) {
          if (!this.isValid) {
            resolve(false);
            return;
          }
          let item = this.blockArr[i][j];
          // 棋子异常 跳过
          if (!item || item.getComponent(gridCmpt).getMoveState()) continue;
          // 棋子已经在列表内 跳过
          if (this.checkExist(item.getComponent(gridCmpt), samelist)) continue;
          // 棋子横向检测，返回满足条件的，不足3个返回[]
          let hor: gridCmpt[] = this._checkHorizontal(item.getComponent(gridCmpt));
          // 棋子纵向检测，返回满足条件的，不足3个返回[]
          let ver: gridCmpt[] = this._checkVertical(item.getComponent(gridCmpt));
          // 横竖都满足3个或3个以上
          if (hor.length >= 3 && ver.length >= 3) {

            hor = hor.slice(1, hor.length);//将自己去掉一个（重复） 返回的方法保证了第一个一定是自己
            hor = hor.concat(ver); // 横竖放在一起
            samelist.push(hor);
          }
        }
      }


      for (let i = 0; i < this.H; i++) {
        for (let j = 0; j < this.V; j++) {
          let item = this.blockArr[i][j];
          // 棋子异常 跳过

          if (!item || item.getComponent(gridCmpt).getMoveState()) continue;
          // 棋子已经在列表内 跳过

          if (this.checkExist(item.getComponent(gridCmpt), samelist)) continue;
          // 棋子横向检测，返回满足条件的，不足3个返回[]

          let hor: gridCmpt[] = this._checkHorizontal(item.getComponent(gridCmpt));
          // 棋子纵向检测，返回满足条件的，不足3个返回[]

          let ver: gridCmpt[] = this._checkVertical(item.getComponent(gridCmpt));
          // 横轴满足条件
          if (hor.length >= 3) {
            samelist.push(hor);
          }
          // 纵轴满足条件
          else if (ver.length >= 3) {
            samelist.push(ver);
          }
        }
      }

      let tian: boolean = false;
      // 什么都不满足且是操作行为时，进行田字检测
      // if ((samelist.length == 0 || (samelist.length == 1 && samelist[0].length == 3)) && control && !result) {
      if ((samelist.length == 0 || (samelist.length == 1 && samelist[0].length == 3)) && !result && !this.isWin) {
        let tempList = [];
        // 整个棋盘循环检测
        for (let i = 0; i < this.H; i++) {
          for (let j = 0; j < this.V; j++) {
            if (!this.isValid) {
              resolve(false);
              return;
            }
            let item = this.blockArr[i][j];
            // 棋子异常 跳过
            if (!item || item.getComponent(gridCmpt).getMoveState()) continue;
            // 棋子已经在列表内 跳过
            if (this.checkExist(item.getComponent(gridCmpt), tempList)) continue;
            // 棋子田字检测，返回满足条件的，不等于4个返回[]
            let hor: gridCmpt[] = this._checkTIAN(item.getComponent(gridCmpt));

            // 满足田字
            if (hor.length == 4) {
              tian = true;
              tempList.push(hor);
            }
          }
        }
        if (tempList.length != 0) {
          samelist = tempList;
        }
      }
      // 触发回调，长度为0时 回调的判定无法触发
      cb && cb(!!samelist.length);
      await this.handleSamelist(samelist, tian);
      let bool = !!samelist.length;
      resolve(bool);
    })
  }

  /**
   * 结果列表，进一步判断每一组元素是否合法
   * @param samelist [Element[]]  最多有三组数据  横轴的可消除数据  纵轴的可消除数据  横竖轴同时满足的可消除数据组合
   * @returns
   */
  private async handleSamelist(samelist: any[], tian: boolean) {
    return new Promise(async resolve => {
      if (samelist.length < 1) {
        resolve("");
        return;
      }
      // 再次去重，防止上面出现问题
      this._deleteDuplicates(samelist);
      if (!tian) {
        //0:去掉不合法的
        samelist = this.jugetLegitimate(samelist);
      }

      // 随机一个音效  todo 后续添加UI
      let soundList = ['combo_cool', 'combo_excellent', 'combo_good', 'combo_perfect', 'combo_great'];
      let rand = Math.floor(Math.random() * soundList.length);
      //1:移除
      for (let i = 0; i < samelist.length; i++) {
        let item = samelist[i];
        if (item.length < 3) continue;
        if (item.length > 3) {

          await this.synthesisBomb(item, tian);

          App.audio.play(soundList[rand])
          let tip = instantiate(this.tipSp);
          this.effNode.addChild(tip);
          // tip.setPosition(Math.floor(Math.random()*400)-200,Math.floor(Math.random()*500)-250);
          tip.setPosition(0, 330);

          tip.getComponent(sp.Skeleton).setAnimation(0, 'a' + (rand + 1), true);

          continue;
        }
        if (item.length > 3) {
        } else {
          App.audio.play('combo');
        }

        for (let j = 0; j < item.length; j++) {
          let ele: gridCmpt = item[j];
          /** 在这里检测糖果四周的障碍物 */
          let listAround = this.getAroundGrid(ele)
          let obstacleList = this.getObstacleList(listAround);
          if (obstacleList.length > 0) {
            for (let m = 0; m < obstacleList.length; m++) {
              this.destroyGridAndGetScore(obstacleList[m].getComponent(gridCmpt));
            }
          }
          this.destroyGridAndGetScore(ele);
        }
      }
      await ToolsHelper.delayTime(0.1);
      await this.checkMoveDown();
      resolve("");
    });
  }

  /**
   * 结果列表，进一步判断每一组元素是否合法
   * @param samelist [Element[]]  最多有三组数据  横轴的可消除数据  纵轴的可消除数据  横竖轴同时满足的可消除数据组合
   * @returns
   */
  private async handleSamelistBefore(samelist: any[], tian: boolean) {
    return new Promise(async resolve => {
      if (samelist.length < 1) {
        resolve("");
        return;
      }
      // 再次去重，防止上面出现问题
      this._deleteDuplicates(samelist);
      if (!tian) {
        //0:去掉不合法的
        samelist = this.jugetLegitimate(samelist);
      }

      // 随机一个音效  todo 后续添加UI
      let soundList = ['combo_cool', 'combo_excellent', 'combo_good', 'combo_perfect', 'combo_great'];
      let rand = Math.floor(Math.random() * soundList.length);
      //1:移除
      for (let i = 0; i < samelist.length; i++) {
        let item = samelist[i];
        if (item.length < 3) continue;
        if (item.length > 3) {
          await this.synthesisBomb(item, tian);
          App.audio.play(soundList[rand])
          let tip = instantiate(this.tipSp);
          this.effNode.addChild(tip);
          // tip.setPosition(Math.floor(Math.random()*400)-200,Math.floor(Math.random()*500)-250);
          tip.setPosition(0, 330);

          tip.getComponent(sp.Skeleton).setAnimation(0, 'a' + (rand + 1), true);

          continue;
        }
        if (item.length > 3) {
        } else {
          App.audio.play('combo');
        }

        for (let j = 0; j < item.length; j++) {
          let ele: gridCmpt = item[j];
          /** 在这里检测糖果四周的障碍物 */
          let listAround = this.getAroundGrid(ele)
          let obstacleList = this.getObstacleList(listAround);
          if (obstacleList.length > 0) {
            for (let m = 0; m < obstacleList.length; m++) {
              this.destroyGridAndGetScore(obstacleList[m].getComponent(gridCmpt));
            }
          }
          this.destroyGridAndGetScore(ele);
        }
      }
      // await ToolsHelper.delayTime(0.2);
      resolve("");
    });
  }

  /** 消除并获得积分 */
  destroyGridAndGetScore(ele: gridCmpt) {
    // 新增：处理冰块层数减少
    if (ele.hasIce()) {
      console.log(`处理冰块消除: ${ele.h},${ele.v}, 当前层数: ${ele.iceLayerCount}`);
      let reduced = ele.reduceIceLayer();
      if (reduced && ele.iceLayerCount > 0) {
        // 冰块层数减少但未完全消除，只播放特效，不销毁节点
        let particle = instantiate(this.particlePre);
        this.effNode.addChild(particle);
        particle.children.forEach(item => {
          item.active = +item.name == ele.type;
        });
        particle.setPosition(this.blockPosArr[ele.h][ele.v]);

        let bomb = instantiate(this.bombPre);
        this.effNode.addChild(bomb);
        bomb.setPosition(this.blockPosArr[ele.h][ele.v]);

        console.log(`冰块层数减少成功: ${ele.h},${ele.v} -> ${ele.iceLayerCount}`);
        // 新增：冰块减少时刷新目标数量
        this.updateTargetCount();
        return; // 不销毁节点，只减少层数
      }
    }

    // 原有逻辑：完全销毁格子
    let particle = instantiate(this.particlePre);
    this.effNode.addChild(particle);
    particle.children.forEach(item => {
      item.active = +item.name == ele.type;
    })
    let tp = ele.type;
    if (!ele || !ele.node) return;
    let worldPosition = ele.node.worldPosition
    this.flyItem(tp, worldPosition);
    this.addScoreByType(tp);
    particle.setPosition(this.blockPosArr[ele.h][ele.v]);

    let bomb = instantiate(this.bombPre);
    this.effNode.addChild(bomb);
    bomb.setPosition(this.blockPosArr[ele.h][ele.v]);

    this.blockArr[ele.h][ele.v] = null;
    ele.node.destroy();
  }

  /** 获取障碍物列表 */
  getObstacleList(list: Node[]) {
    let obstacleList = [];
    for (let i = 0; i < list.length; i++) {
      let type = list[i].getComponent(gridCmpt).type;
      if (App.gameLogic.sideObstacleList.indexOf(type) > -1) {
        obstacleList.push(list[i]);
      }
    }
    return obstacleList;
  }

  /** 获取一颗糖果四周的糖果 */
  getAroundGrid(grid: gridCmpt) {
    // 修改：允许障碍物被正确处理，不再直接返回空数组
    // if (grid.type > Constant.NormalType) return [];
    let h = grid.h;
    let v = grid.v;
    let left = h - 1;
    let right = h + 1;
    let up = v + 1;
    let down = v - 1;
    let list = [];
    if (left >= 0 && this.blockArr[left][v]) {
      list.push(this.blockArr[left][v]);
    }
    if (right < Constant.layCount && this.blockArr[right][v]) {
      list.push(this.blockArr[right][v]);
    }
    if (down >= 0 && this.blockArr[h][down]) {
      list.push(this.blockArr[h][down]);
    }
    if (up < Constant.layCount && this.blockArr[h][up]) {
      list.push(this.blockArr[h][up]);
    }
    return list;
  }

  /** 炸弹消除 */
  private async handleSamelistBomb(samelist: any[]) {
    return new Promise(async resolve => {
      if (samelist.length < 1) {
        resolve("");
        return;
      }
      let soundList = ['combo_cool', 'combo_excellent', 'combo_good', 'combo_perfect', 'combo_great'];
      let rand = Math.floor(Math.random() * soundList.length);
      this.scheduleOnce(() => {
        if (this.isValid) {
          App.audio.play(soundList[rand])
          let tip = instantiate(this.tipSp);
          this.effNode.addChild(tip);
          // tip.setPosition(Math.floor(Math.random()*400)-200,Math.floor(Math.random()*500)-250);
          tip.setPosition(0, 330);
          tip.getComponent(sp.Skeleton).setAnimation(0, 'a' + (rand + 1), true);
        }
      }, 0.2);
      // 移除
      for (let i = 0; i < samelist.length; i++) {
        let ele: gridCmpt = samelist[i];
        if (!ele || !ele.node) continue;
        /** 在这里检测糖果四周的障碍物 */
        let listAround = this.getAroundGrid(ele)
        let obstacleList = this.getObstacleList(listAround);
        if (obstacleList.length > 0) {
          for (let m = 0; m < obstacleList.length; m++) {
            this.destroyGridAndGetScore(obstacleList[m].getComponent(gridCmpt));
          }
        }
        this.destroyGridAndGetScore(ele);
      }

      await ToolsHelper.delayTime(0.3);
      await this.checkMoveDown();
      resolve("");
    });
  }

  /** 炸弹消除 */
  private async handleSamelistBombBefore(samelist: any[]) {
    return new Promise(async resolve => {
      if (samelist.length < 1) {
        resolve("");
        return;
      }
      let soundList = ['combo_cool', 'combo_excellent', 'combo_good', 'combo_perfect', 'combo_great'];
      let rand = Math.floor(Math.random() * soundList.length);
      this.scheduleOnce(() => {
        if (this.isValid) {
          App.audio.play(soundList[rand])
          let tip = instantiate(this.tipSp);
          this.effNode.addChild(tip);
          // tip.setPosition(Math.floor(Math.random()*400)-200,Math.floor(Math.random()*500)-250);
          tip.setPosition(0, 330);
          tip.getComponent(sp.Skeleton).setAnimation(0, 'a' + (rand + 1), true);
        }
      }, 0.2);
      // 移除
      for (let i = 0; i < samelist.length; i++) {
        let ele: gridCmpt = samelist[i];
        if (!ele || !ele.node) continue;
        /** 在这里检测糖果四周的障碍物 */
        let listAround = this.getAroundGrid(ele)
        let obstacleList = this.getObstacleList(listAround);
        if (obstacleList.length > 0) {
          for (let m = 0; m < obstacleList.length; m++) {
            this.destroyGridAndGetScore(obstacleList[m].getComponent(gridCmpt));
          }
        }
        this.destroyGridAndGetScore(ele);
      }

      resolve("");
    });
  }

  /** 合成炸弹 */
  synthesisBomb(item: gridCmpt[], tian: boolean) {
    return new Promise(resolve => {

      /** 先找当前item中是否包含curTwo,包含就以curTwo为中心合成 */
      let center: gridCmpt = null;
      for (let j = 0; j < item.length; j++) {
        for (let m = 0; m < this.curTwo.length; m++) {
          if (item[j].h == this.curTwo[m].h && item[j].v == this.curTwo[m].v) {
            center = item[j];
            break;
          }
        }
      }
      // 没有就随机一个中心点 取长度的一半来随机
      if (!center) {
        center = item[Math.floor(item.length / 2)];
      }
      let bombType = App.gameLogic.getBombType(item, tian);
      App.audio.play("ui_banner_up_hide");
      let count = 0;
      let count1 = 0;
      for (let j = 0; j < item.length; j++) {
        let ele: gridCmpt = item[j];
        let tp = ele.type;
        if (!ele || !ele.node) continue;
        let worldPosition = ele.node.worldPosition;
        this.flyItem(tp, worldPosition);
        this.addScoreByType(tp);
        count1++;
        tween(ele.node).to(0.1, { position: this.blockPosArr[center.h][center.v] }).call((target) => {
          count++;
          let gt = target.getComponent(gridCmpt);
          console.log(gt.h, gt.v)
          if (gt.h == center.h && gt.v == center.v) {
            gt.setType(bombType);
          } else {
            this.blockArr[gt.h][gt.v] = null;
            gt.node.destroy();
          }
          if (count == count1) {
            resolve("");
          }
        }).start();
      }
    })
  }

  /**
   * 去掉不合法的
   * @param samelist  [Element[]]
   */
  private jugetLegitimate(samelist: any[]) {
    let arr: any[] = [];
    for (let i = 0; i < samelist.length; i++) {
      let itemlist = samelist[i];
      let bool: boolean = this.startJuge(itemlist);
      if (bool) {
        arr.push(itemlist);
      }
    }
    return arr;
  }

  /**
   * 校正数据，看是否满足消除的条件
   * @param list
   * @private
   */
  private startJuge(list: gridCmpt[]): boolean {
    let bool = false;
    let len = list.length;
    switch (len) {
      case 3:
        bool = this._atTheSameHorOrVer(list);
        break;

      case 4:
        bool = this._atTheSameHorOrVer(list);
        break;

      case 5:
        bool = this._atTheSameHorOrVer(list);
        if (!bool) {
          bool = this._atLeastThreeSameHorAndVer(list);
        }
        break;

      case 6:
        bool = this._atLeastThreeSameHorAndVer(list);
        break;

      case 7:
        bool = this._atLeastThreeSameHorAndVer(list);
        break;

      default://全在行或者列
        bool = this._atLeastThreeSameHorAndVer(list);
        break;

    }
    return bool;
  }

  /**
   * 至少有三个同行且三个同列
   * @param list
   * @returns
   */
  private _atLeastThreeSameHorAndVer(list: gridCmpt[]): boolean {
    let bool = false;
    let count = 0;
    //同一列
    for (let i = 0; i < list.length; i++) {
      let item1 = list[i];
      for (let j = 0; j < list.length; j++) {
        let item2 = list[j];
        if (item1.data.h == item2.data.h) {
          count++;
          break;
        }
      }
    }
    if (count < 3) return bool;
    count = 0;
    //同一行
    for (let i = 0; i < list.length; i++) {
      let item1 = list[i];
      for (let j = 0; j < list.length; j++) {
        let item2 = list[j];
        if (item1.data.v == item2.data.v) {
          count++;
          break;
        }
      }
    }
    if (count < 3) return bool;
    return true;
  }

  /**
   * 处在同一行/或者同一列
   * @param list
   * @returns
   */
  private _atTheSameHorOrVer(list: gridCmpt[]): boolean {
    let item = list[0];
    let bool = true;
    //同一列
    for (let i = 0; i < list.length; i++) {
      if (item.data.h != list[i].data.h) {
        bool = false;
        break;
      }
    }
    if (bool) return bool;
    bool = true;
    //同一行
    for (let i = 0; i < list.length; i++) {
      if (item.data.v != list[i].data.v) {
        bool = false;
        break;
      }
    }
    return bool;
  }

  /**
   * 去重复
   */
  private _deleteDuplicates(samelist: any[]) {
    for (let i = 0; i < samelist.length; i++) {
      let itemlist = samelist[i];
      let bool = true;
      do {
        let count = 0;
        for (let m = 0; m < itemlist.length - 1; m++) {
          for (let n = m + 1; n < itemlist.length; n++) {
            if (itemlist[m].data.h == itemlist[n].data.h && itemlist[m].data.v == itemlist[n].data.v) {
              samelist[i].splice(i, 1);
              count++;
              console.log('------------repeat----------');
              break;
            }
          }
        }
        bool = count > 0 ? true : false;
      } while (bool);
    }
  }

  /**
   * 以当前滑块为中心进行田字检查
   * @param {gridCmpt} item
   */
  private _checkTIAN(item: gridCmpt): gridCmpt[] {
    let right: gridCmpt[] = [item];
    let left: gridCmpt[] = [item];
    let down: gridCmpt[] = [item];
    let up: gridCmpt[] = [item];
    let startX = item.data.h;
    let startY = item.data.v;

    let rightUp: Boolean = false;
    let leftUp: Boolean = false;
    let rightDown: Boolean = false;
    let leftDown: Boolean = false;

    // 右边
    for (let i = startX + 1; i < this.H; i++) {
      if (!this.blockArr[i][startY]) break;
      let ele = this.blockArr[i][startY].getComponent(gridCmpt);
      if (!ele || item.getMoveState()) break;
      if (ele.type == item.type && ele.type < Constant.NormalType) {
        right.push(ele);
      } else {
        break;
      }
    }
    // 右上检测
    if (startX == this.blockArr.length - 1 || startY == this.blockArr[startX + 1].length - 1 || !this.blockArr[startX + 1][startY + 1]) {

    } else {
      let ele = this.blockArr[startX + 1][startY + 1].getComponent(gridCmpt);
      if (ele && !item.getMoveState()) {
        if (ele.type == item.type && ele.type < Constant.NormalType) {
          rightUp = true;
        }
      }
    }

    // 左上检测
    if (startX == 0 || startY == this.blockArr[startX - 1].length - 1 || !this.blockArr[startX - 1][startY + 1]) {

    } else {
      let ele = this.blockArr[startX - 1][startY + 1].getComponent(gridCmpt);
      if (ele && !item.getMoveState()) {
        if (ele.type == item.type && ele.type < Constant.NormalType) {
          leftUp = true;
        }
      }
    }

    // 右下检测
    if (startY == 0 || startX == this.blockArr.length - 1 || !this.blockArr[startX + 1][startY - 1]) {

    } else {
      let ele = this.blockArr[startX + 1][startY - 1].getComponent(gridCmpt);
      if (ele && !item.getMoveState()) {
        if (ele.type == item.type && ele.type < Constant.NormalType) {
          rightDown = true;
        }
      }
    }

    // 左下检测
    if (startX == 0 || startY == 0 || !this.blockArr[startX - 1][startY - 1]) {

    } else {
      let ele = this.blockArr[startX - 1][startY - 1].getComponent(gridCmpt);
      if (ele && !item.getMoveState()) {
        if (ele.type == item.type && ele.type < Constant.NormalType) {
          leftDown = true;
        }
      }
    }

    if (!leftUp && !leftDown && !rightDown && !rightUp) {
      return [];
    }


    // 上边
    for (let i = startY + 1; i < this.V; i++) {
      if (!this.blockArr[startX][i]) break;
      let ele = this.blockArr[startX][i].getComponent(gridCmpt);
      if (!ele || item.getMoveState()) break;
      if (ele.type == item.type && ele.type < Constant.NormalType) {
        up.push(ele);
      } else {
        break;
      }
    }
    // 下边
    for (let i = startY - 1; i >= 0; i--) {
      if (i < 0) break;
      if (!this.blockArr[startX][i]) break;
      let ele = this.blockArr[startX][i].getComponent(gridCmpt);
      if (!ele || item.getMoveState()) break;
      if (ele.type == item.type && ele.type < Constant.NormalType) {
        down.push(ele);
      } else {
        break;
      }
    }
    // 左边
    for (let i = startX - 1; i >= 0; i--) {
      if (i < 0) break;
      if (!this.blockArr[i][startY]) break;
      let ele = this.blockArr[i][startY].getComponent(gridCmpt);
      if (!ele || item.getMoveState()) break;
      if (ele.type == item.type && ele.type < Constant.NormalType) {
        left.push(ele);
      } else {
        break;
      }
    }
    let arr: gridCmpt[] = [item];

    if (leftUp && left.length == 2 && up.length == 2) {
      arr.push(left[1]); // 横竖放在一起
      arr.push(up[1]); // 横竖放在一起
      arr.push(this.blockArr[startX - 1][startY + 1].getComponent(gridCmpt)); // 横竖放在一起

      return arr;
    } else if (leftDown && left.length == 2 && down.length == 2) {
      arr.push(left[1]); // 横竖放在一起
      arr.push(down[1]); // 横竖放在一起
      arr.push(this.blockArr[startX - 1][startY - 1].getComponent(gridCmpt)); // 横竖放在一起
      return arr;
    } else if (rightDown && right.length == 2 && down.length == 2) {
      arr.push(right[1]); // 横竖放在一起
      arr.push(down[1]); // 横竖放在一起
      arr.push(this.blockArr[startX + 1][startY - 1].getComponent(gridCmpt)); // 横竖放在一起
      return arr;
    } else if (rightUp && right.length == 2 && up.length == 2) {
      arr.push(right[1]); // 横竖放在一起
      arr.push(up[1]); // 横竖放在一起
      arr.push(this.blockArr[startX + 1][startY + 1].getComponent(gridCmpt)); // 横竖放在一起
      return arr;
    }
    return [];

  }

  /**
   * 以当前滑块为中心沿水平方向检查
   * @param {gridCmpt} item
   */
  private _checkHorizontal(item: gridCmpt): gridCmpt[] {
    let arr: gridCmpt[] = [item];
    let startX = item.data.h;
    let startY = item.data.v;
    // 右边
    for (let i = startX + 1; i < this.H; i++) {
      if (!this.blockArr[i][startY]) break;
      let ele = this.blockArr[i][startY].getComponent(gridCmpt);
      if (!ele || item.getMoveState()) break;
      if (ele.type == item.type && ele.type < Constant.NormalType) {
        arr.push(ele);
      } else {
        break;
      }
    }
    // 左边
    for (let i = startX - 1; i >= 0; i--) {
      if (i < 0) break;
      if (!this.blockArr[i][startY]) break;
      let ele = this.blockArr[i][startY].getComponent(gridCmpt);
      if (!ele || item.getMoveState()) break;
      if (ele.type == item.type && ele.type < Constant.NormalType) {
        arr.push(ele);
      } else {
        break;
      }
    }
    if (arr.length < 3) return [];
    return arr;
  }

  /**
   * 以当前滑块为中心沿竖直方向检查
   * @param {gridCmpt} item
   */
  private _checkVertical(item: gridCmpt): gridCmpt[] {
    let arr: gridCmpt[] = [item];
    let startX = item.data.h;
    let startY = item.data.v;
    // 上边
    for (let i = startY + 1; i < this.V; i++) {
      if (!this.blockArr[startX][i]) break;
      let ele = this.blockArr[startX][i].getComponent(gridCmpt);
      if (!ele || item.getMoveState()) break;
      if (ele.type == item.type && ele.type < Constant.NormalType) {
        arr.push(ele);
      } else {
        break;
      }
    }
    // 下边
    for (let i = startY - 1; i >= 0; i--) {
      if (i < 0) break;
      if (!this.blockArr[startX][i]) break;
      let ele = this.blockArr[startX][i].getComponent(gridCmpt);
      if (!ele || item.getMoveState()) break;
      if (ele.type == item.type && ele.type < Constant.NormalType) {
        arr.push(ele);
      } else {
        break;
      }
    }
    if (arr.length < 3) return [];
    return arr;
  }

  /** 数据交换，网格位置交换 */
  changeData(item1: gridCmpt, item2: gridCmpt) {
    /** 数据交换 */
    let temp = item1.data;
    item1.data = item2.data;
    item2.data = temp;

    /** 位置交换 */
    let x1 = item1.data.h;
    let y1 = item1.data.v;
    let x2 = item2.data.h;
    let y2 = item2.data.v;
    let pTemp = this.blockArr[x1][y1];
    this.blockArr[x1][y1] = this.blockArr[x2][y2]
    this.blockArr[x2][y2] = pTemp;
    this.blockArr[x1][y1].getComponent(gridCmpt).initData(this.blockArr[x1][y1].getComponent(gridCmpt).data.h, this.blockArr[x1][y1].getComponent(gridCmpt).data.v);
    this.blockArr[x2][y2].getComponent(gridCmpt).initData(this.blockArr[x2][y2].getComponent(gridCmpt).data.h, this.blockArr[x2][y2].getComponent(gridCmpt).data.v);
  }

  /** 是否点击在方块上 */
  checkClickOnBlock(pos: Vec3): gridCmpt {
    if (!this.isValid) return;
    if (this.blockArr.length < 1) return;
    for (let i = 0; i < this.H; i++) {
      for (let j = 0; j < this.V; j++) {
        let block = this.blockArr[i][j];
        if (block && block.getComponent(gridCmpt).type < Constant.NormalType) {
          if (block.getComponent(gridCmpt).isInside(pos)) {
            return block.getComponent(gridCmpt);
          }
        }
      }
    }
    return null;
  }

  /** 消除后向下滑动 */
  async checkMoveDown() {
    return new Promise(async resolve => {
      for (let i = 0; i < this.H; i++) {
        let count = 0;
        for (let j = 0; j < this.V; j++) {
          if (!this.isValid) return;
          let block = this.blockArr[i][j];
          let isHide = App.gameLogic.checkInHideList(i, j);
          if (block == null || !block.isValid) {
            if (!isHide) {
              count++;
            } else {
              //当前格子以下是不是全是边界空的，是边界空的就忽略，否则就+1
              let bool = App.gameLogic.checkAllInHideList(i, j);
              if (!bool && count > 0) {
                count++;
              }
            }
          } else if (block && count > 0) {
            let count1 = await this.getDownLastCount(i, j, count);
            this.blockArr[i][j] = null;
            this.blockArr[i][j - count1] = block;
            block.getComponent(gridCmpt).initData(i, j - count1);
            this.resetTimeInterval();
            tween(block).to(0.5, { position: this.blockPosArr[i][j - count1] }, { easing: 'backOut' }).call(() => {

            }).start();
          }
        }
      }
      // await ToolsHelper.delayTime(0.2);
      await this.checkReplenishBlock();
      resolve("");
    });
  }

  /** 获取最终下落的格子数 */
  async getDownLastCount(i, j, count): Promise<number> {
    return new Promise(resolve => {
      let tempCount = 0;
      let func = (i, j, count) => {
        tempCount = count;
        let bool = App.gameLogic.checkInHideList(i, j - count);
        if (bool || this.blockArr[i][j - count]) {
          func(i, j, count - 1);
        }
      }
      func(i, j, count);
      resolve(tempCount);
    })
  }

  /** 补充新方块填补空缺 */
  async checkReplenishBlock() {
    return new Promise(async resolve => {
      let count1 = 0;
      let count2 = 0;
      for (let i = 0; i < this.H; i++) {
        for (let j = 0; j < this.V; j++) {
          let block = this.blockArr[i][j];
          let isHide = App.gameLogic.checkInHideList(i, j);
          if (!block && !isHide) {
            let pos = this.blockPosArr[i][this.V - 1]
            let block = this.addBlock(i, j, v3(pos.x, pos.y + Constant.Width + 20, 1));
            this.blockArr[i][j] = block;
            this.resetTimeInterval();
            count1++;
            tween(block).to(0.5, { position: this.blockPosArr[i][j] }, { easing: 'backOut' }).call(() => {
              count2++;
              if (count1 == count2) {
                resolve("");
              }
            }).start();
          }
        }
      }
      // await ToolsHelper.delayTime(0.5);
      // resolve("");
    });
  }

  async initLayout() {
    this.clearData();
    this.baseMapNode.destroyAllChildren();
    await this.gridMgr.initGrid();
    this.hideList = App.gameLogic.hideList;
    let gap = 0;
    let count = 0;
    let width = Constant.Width;

    let targetCount = 0;
    let targetIdx = 0;
    /** 先初始化网格坐标 */
    for (let i = 0; i < this.H; i++) {
      this.blockPosArr.push([]);
      this.blockArr.push([]);
      for (let j = 0; j < this.V; j++) {
        let xx = (width + gap) * (i + 0) - (width + gap) * (this.H - 1) / 2;
        let yy = (width + gap) * (j + 0) - (width + gap) * (this.V - 1) / 2;
        let pos = v3(xx, yy, 1);
        this.blockPosArr[i][j] = pos;
        this.blockArr[i][j] = null;
        let instantiate1 = instantiate(this.baseMapPre);
        instantiate1.setParent(this.baseMapNode);
        instantiate1.setPosition(pos);
        // console.log(pos.x,pos.y)
      }
    }

    // 新增：根据数组配置生成关卡布局
    if (this.data.layout && this.data.layout.length > 0) {
      console.log('使用数组配置生成关卡布局');
      await this.initLayoutByArray();
    } else {
      console.log('使用原有配置生成关卡布局');
      /** 先初始化障碍物 */
      let obsList = this.coutArr[0];
      let count2 = 0;
      if (obsList[0] > Constant.NormalType) {
        let len = obsList[1];
        let c1 = Math.ceil(Math.sqrt(len));
        let start = Math.floor((Constant.layCount - c1) / 2);
        let end = start + c1;
        // console.log("start=============== " + start);
        // console.log("end=============== " + end);
        for (let m = start; m < end; m++) {
          for (let n = start; n < end; n++) {
            if (count2 < len) {
              let pos = this.blockPosArr[m][n];
              let block = this.addBlock(m, n, pos, obsList[0]);
              block.setScale(v3(0, 0, 0));
              tween(block).to(0.5, { scale: v3(1, 1, 1) }).start();
              this.blockArr[m][n] = block;
            }
            count2++;
          }
        }
      }

      /** 普通糖果 */
      for (let i = 0; i < this.H; i++) {
        for (let j = 0; j < this.V; j++) {
          if (App.gameLogic.hideFullList.length < this.H * this.V) {
            App.gameLogic.hideFullList.push([i, j]);
          }
          let xx = (width + gap) * (i + 0) - (width + gap) * (this.H - 1) / 2;
          let yy = (width + gap) * (j + 0) - (width + gap) * (this.V - 1) / 2;
          let pos = v3(xx, yy, 1);
          if (App.gameLogic.checkInHideList(i, j)) {
            this.blockArr[i][j] = null;
            continue;
          }
          count++;

          /** 障碍物 */
          let type = -1;
          // let targetlist = this.coutArr[targetIdx];
          // if (targetlist) {
          //     if (targetCount < targetlist[1]) {
          //         type = targetlist[0];
          //         targetCount++;
          //     }
          //     else {
          //         targetIdx++;
          //         targetCount = 0;
          //     }
          // }
          if (this.blockArr[i][j]) continue;
          let block = this.addBlock(i, j, pos, type);
          block.setScale(v3(0, 0, 0));
          tween(block).to(count / 100, { scale: v3(1, 1, 1) }).start();
          this.blockArr[i][j] = block;
        }
      }
    }

    await ToolsHelper.delayTime(0.8);
    // this.checkAgain();
    /** 进入游戏选择的道具炸弹 */
    let list = App.gameLogic.toolsArr;
    for (let i = 0; i < list.length; i++) {
      this.throwTools(list[i]);
    }
    App.gameLogic.toolsArr = [];

    this.checkAgain()
  }

  // 新增：根据数组配置初始化关卡布局
  async initLayoutByArray() {
    let gap = 0;
    let width = Constant.Width;
    let count = 0;

    // 新增：检查布局是否有解，如果无解则使用随机生成
    if (!this.hasValidMoves()) {
      console.log('检测到无解布局，使用随机生成');
      await this.initRandomLayout();
      return;
    }

    for (let i = 0; i < this.H; i++) {
      for (let j = 0; j < this.V; j++) {
        if (App.gameLogic.hideFullList.length < this.H * this.V) {
          App.gameLogic.hideFullList.push([i, j]);
        }

        let xx = (width + gap) * (i + 0) - (width + gap) * (this.H - 1) / 2;
        let yy = (width + gap) * (j + 0) - (width + gap) * (this.V - 1) / 2;
        let pos = v3(xx, yy, 1);

        if (App.gameLogic.checkInHideList(i, j)) {
          this.blockArr[i][j] = null;
          continue;
        }

        // 从布局数组中获取格子类型
        let type = -1;
        let iceLayers = 0;
        let hasIce = false;
        if (this.data.layout && this.data.layout[i] && this.data.layout[i][j] !== undefined) {
          type = this.data.layout[i][j];
        }
        if (this.data.obstacleLayers && this.data.obstacleLayers[i] && this.data.obstacleLayers[i][j] !== undefined) {
          iceLayers = this.data.obstacleLayers[i][j];
          hasIce = iceLayers > 0;
        }
        // 只有当type为-1且没有冰块时才不生成格子
        if ((type === -1 || type === 0) && !hasIce) {
          this.blockArr[i][j] = null;
          continue;
        }
        count++;
        let block = this.addBlockWithIce(i, j, pos, type, iceLayers);
        block.setScale(v3(0, 0, 0));
        tween(block).to(count / 100, { scale: v3(1, 1, 1) }).start();
        this.blockArr[i][j] = block;
      }
    }
  }

  // 新增：检查布局是否有有效移动
  hasValidMoves(): boolean {
    if (!this.data.layout || this.data.layout.length === 0) {
      return false;
    }

    // 检查是否有连续三个相同类型的糖果
    for (let i = 0; i < this.H; i++) {
      for (let j = 0; j < this.V - 2; j++) {
        if (this.data.layout[i][j] === this.data.layout[i][j + 1] &&
          this.data.layout[i][j] === this.data.layout[i][j + 2]) {
          return true;
        }
      }
    }

    for (let i = 0; i < this.H - 2; i++) {
      for (let j = 0; j < this.V; j++) {
        if (this.data.layout[i][j] === this.data.layout[i + 1][j] &&
          this.data.layout[i][j] === this.data.layout[i + 2][j]) {
          return true;
        }
      }
    }

    // 检查是否有可交换形成三消的组合
    for (let i = 0; i < this.H; i++) {
      for (let j = 0; j < this.V; j++) {
        // 检查水平交换
        if (j < this.V - 1) {
          let tempLayout = JSON.parse(JSON.stringify(this.data.layout));
          [tempLayout[i][j], tempLayout[i][j + 1]] = [tempLayout[i][j + 1], tempLayout[i][j]];
          if (this.checkHasThreeInRow(tempLayout, i, j) || this.checkHasThreeInRow(tempLayout, i, j + 1)) {
            return true;
          }
        }

        // 检查垂直交换
        if (i < this.H - 1) {
          let tempLayout = JSON.parse(JSON.stringify(this.data.layout));
          [tempLayout[i][j], tempLayout[i + 1][j]] = [tempLayout[i + 1][j], tempLayout[i][j]];
          if (this.checkHasThreeInCol(tempLayout, i, j) || this.checkHasThreeInCol(tempLayout, i + 1, j)) {
            return true;
          }
        }
      }
    }

    return false;
  }

  // 新增：检查行中是否有三消
  checkHasThreeInRow(layout: number[][], row: number, col: number): boolean {
    let type = layout[row][col];
    let count = 1;

    // 向左检查
    for (let j = col - 1; j >= 0; j--) {
      if (layout[row][j] === type) {
        count++;
      } else {
        break;
      }
    }

    // 向右检查
    for (let j = col + 1; j < this.V; j++) {
      if (layout[row][j] === type) {
        count++;
      } else {
        break;
      }
    }

    return count >= 3;
  }

  // 新增：检查列中是否有三消
  checkHasThreeInCol(layout: number[][], row: number, col: number): boolean {
    let type = layout[row][col];
    let count = 1;

    // 向上检查
    for (let i = row + 1; i < this.H; i++) {
      if (layout[i][col] === type) {
        count++;
      } else {
        break;
      }
    }

    // 向下检查
    for (let i = row - 1; i >= 0; i--) {
      if (layout[i][col] === type) {
        count++;
      } else {
        break;
      }
    }

    return count >= 3;
  }

  // 新增：随机生成布局
  async initRandomLayout() {
    let gap = 0;
    let width = Constant.Width;
    let count = 0;

    for (let i = 0; i < this.H; i++) {
      for (let j = 0; j < this.V; j++) {
        if (App.gameLogic.hideFullList.length < this.H * this.V) {
          App.gameLogic.hideFullList.push([i, j]);
        }

        let xx = (width + gap) * (i + 0) - (width + gap) * (this.H - 1) / 2;
        let yy = (width + gap) * (j + 0) - (width + gap) * (this.V - 1) / 2;
        let pos = v3(xx, yy, 1);

        if (App.gameLogic.checkInHideList(i, j)) {
          this.blockArr[i][j] = null;
          continue;
        }

        count++;
        let block = this.addBlock(i, j, pos, -1); // 使用随机类型
        block.setScale(v3(0, 0, 0));
        tween(block).to(count / 100, { scale: v3(1, 1, 1) }).start();
        this.blockArr[i][j] = block;
      }
    }
  }

  addBlock(i: number, j: number, pos: Vec3 = null, type: number = -1) {
    let block = instantiate(this.gridPre);
    this.gridNode.addChild(block);
    block.getComponent(gridCmpt).initData(i, j, type);
    if (pos) {
      block.setPosition(pos);
    }
    return block;
  }

  // 新增：生成带冰块层数的格子
  addBlockWithIce(i: number, j: number, pos: Vec3 = null, type: number = -1, iceLayers: number = 0) {
    let block = instantiate(this.gridPre);
    this.gridNode.addChild(block);
    block.getComponent(gridCmpt).initData(i, j, type, iceLayers);
    if (pos) {
      block.setPosition(pos);
    }
    return block;
  }

  clearData() {
    App.gameLogic.resetHdeList(this.level);
    if (this.blockArr.length < 1) return;
    for (let i = 0; i < this.H; i++) {
      for (let j = 0; j < this.V; j++) {
        let block = this.blockArr[i][j];
        if (block) {
          block.destroy();
        }
      }
    }
    this.blockArr = [];
    this.blockPosArr = [];
    this.isStartChange = false;
    this.isStartTouch = false;
    this.curScore = 0;
    this.isWin = false;
  }

  /** 加积分 */
  addScoreByType(type: number) {
    if (type > this.data.blockRatio.length - 1) {
      type = this.data.blockRatio.length - 1;
    }
    let score = this.data.blockRatio[type];
    this.curScore += score;
    this.updateScorePercent();
  }

  /** 飞舞动画 */
  async flyItem(type: number, pos: Vec3) {
    let idx = this.data.mapData[0].m_id.indexOf(type);
    if (idx < 0) return;
    let item = instantiate(this.gridPre);
    let tempPos = new Vec3();
    let targetPos = new Vec3();
    /** 空间坐标转节点坐标 */
    this.node.getComponent(UITransform).convertToNodeSpaceAR(pos, tempPos)
    this.node.getComponent(UITransform).convertToNodeSpaceAR(this.targetBg.worldPosition, targetPos)
    item.setPosition(tempPos);
    this.node.addChild(item);
    item.getComponent(gridCmpt).setType(type);

    let time = 0.5 + Math.random() * 1;
    item.setScale(0.5, 0.5, 0.5);
    tween(item).to(time, { position: targetPos }, { easing: 'backIn' }).call(() => {
      this.handleLevelTarget(type);
      item.destroy();
      // App.audio.play('Full');
    }).start();
  }

  handleLevelTarget(type: number) {
    for (let i = 0; i < this.coutArr.length; i++) {
      if (type == this.coutArr[i][0]) {
        this.coutArr[i][1]--
        if (this.coutArr[i][1] < 0) {
          this.coutArr[i][1] = 0;
        }
      }
    }
    this.updateTargetCount();
  }

  /*********************************************  btn *********************************************/

  /*********************************************  btn *********************************************/
  /*********************************************  btn *********************************************/
  evtRestart() {
    this.loadExtraData(this.level);
    // Advertise.showVideoAds();
  }

  onClick_testBtn() {
    this.loadExtraData(this.level);
    // this.handleLastSteps();
  }


  /** 购买金币 */
  onClick_buyBtn() {
    App.audio.play('button_click');
    App.view.openView(ViewName.Single.eBuyView);
  }

  /** 添加道具，广告位 */
  onClickAddButton(btnNode: Node) {
    App.audio.play('button_click');
    let type: number = -1;
    switch (btnNode.name) {
      case "addBtn1":
        type = Bomb.bomb;
        break;
      case "addBtn2":
        type = Bomb.hor;
        break;
      case "addBtn3":
        type = Bomb.ver;
        break;
      case "addBtn4":
        type = Bomb.allSame;
        break;
    }
    App.backHome(false, PageIndex.shop);
    // GlobalFuncHelper.setBomb(type,1);
  }

  onClickVideoButton(btnNode: Node) {
    App.audio.play('button_click');
    let type: number = -1;
    switch (btnNode.name) {
      case "video1":
        type = Bomb.bomb;
        break;
      case "video2":
        type = Bomb.hor;
        break;
      case "video3":
        type = Bomb.ver;
        break;
      case "video4":
        type = Bomb.allSame;
        break;
    }
    // Advertise.showVideoAds();

  }

  private isUsingBomb: boolean = false;

  /** 道具 */
  onClickToolButton(btnNode: Node) {
    if (this.getTimeInterval() > 0) {
      App.view.showMsgTips("操作太快")
      return;
    }
    App.audio.play('button_click');
    if (this.isUsingBomb) return;
    this.isUsingBomb = true;
    this.scheduleOnce(() => {
      this.isUsingBomb = false;
      this.isStartChange = false;
      this.isStartTouch = false;
    }, 1);
    let type: number = -1;
    switch (btnNode.name) {
      case "toolBtn1":
        type = Bomb.bomb;
        break;
      case "toolBtn2":
        type = Bomb.hor;
        break;
      case "toolBtn3":
        type = Bomb.ver;
        break;
      case "toolBtn4":
        type = Bomb.allSame;
        break;
    }
    if (!App.gameLogic.decModel) {
      let bombCount = GlobalFuncHelper.getBomb(type);
      if (bombCount <= 0) {
        App.view.showMsgTips("道具数量不足");
        return;
      }
      GlobalFuncHelper.setBomb(type, -1);
    }

    this.setBomb = true;
    this.setBombTipNode.active = true;
    this.setType = type;
    let pos = btnNode.worldPosition;
    // this.throwTools(type, pos);
  }

  /** 提示道具 */
  async onClick_tipsBtn() {
    let list = [];
    for (let i = 0; i < this.H; i++) {
      for (let j = 0; j < this.V; j++) {
        let item = this.blockArr[i][j];
        if (item) {
          let arr = App.gameLogic.checkTipsGroup(item.getComponent(gridCmpt), this.blockArr);
          if (arr.length > 0) {
            let count = 0;
            for (let m = 0; m < arr.length; m++) {
              if (arr[m].getComponent(gridCmpt).type > Constant.NormalType) {
                count++;
              }
            }
            if (count == 0) {
              list.push(arr);
            }
          }
        }
      }
    }
    if (list.length > 0) {
      let rand = Math.floor(Math.random() * list.length);
      let tipsList = list[rand];
      tipsList.forEach(item => {
        item.getComponent(gridCmpt).showTips();
      })
    } else {
      App.view.showMsgTips("没有可以交换的糖果了");
      await ToolsHelper.delayTime(0.5);
      this.loadExtraData(this.level);
    }
  }
}